home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume4 / settz < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  59.2 KB

  1. Subject: time conversion / time zone system
  2. Newsgroups: mod.sources
  3. Approved: jpn@panda.UUCP
  4.  
  5. Mod.sources:  Volume 4, Issue 14
  6. Submitted by: talcott!seismo!elsie!ado
  7.  
  8. #! /bin/sh
  9. # This is a shell archive, meaning:
  10. # 1. Remove everything above the #! /bin/sh line.
  11. # 2. Save the resulting text in a file.
  12. # 3. Execute the file with /bin/sh (not csh) to create the files:
  13. #    README
  14. #    Makefile
  15. #    settz.3
  16. #    tzfile.5
  17. #    tzcomp.8
  18. #    tzfile.h
  19. #    tzcomp.c
  20. #    scheck.c
  21. #    strchr.c
  22. #    mkdir.c
  23. #    tzdump.c
  24. #    settz.c
  25. #    years.sh
  26. #    asia
  27. #    australasia
  28. #    europe
  29. #    etcetera
  30. #    northamerica
  31. #    pacificnew
  32. # This archive created: Fri Mar  7 17:02:24 1986
  33. export PATH; PATH=/bin:$PATH
  34. echo shar: extracting "'README'" '(620 characters)'
  35. if test -f 'README'
  36. then
  37.     echo shar: will not over-write existing file "'README'"
  38. else
  39. cat << \SHAR_EOF > 'README'
  40. @(#)README    2.1
  41.  
  42. Please send comments or information to seismo!elsie!ado (with, perhaps,
  43. carbon copes to cbosgd!mark, seismo!linus!encore!necis!geo, and
  44. seismo!munnari!kre, who are responsible for any good ideas that show up here).
  45.  
  46. Historical local time information has been included here not because it should
  47. be part of the standard (or, indeed, anyone's product), but rather to:
  48.  
  49. *    give people an idea of the variety of local time rules that have
  50.     existed in the past and thus an idea of the variety that may be
  51.     expected in the future;
  52.  
  53. *    provide a test of the generality of the local time rule description
  54.     system.
  55. SHAR_EOF
  56. if test 620 -ne "`wc -c < 'README'`"
  57. then
  58.     echo shar: error transmitting "'README'" '(should have been 620 characters)'
  59. fi
  60. fi
  61. echo shar: extracting "'Makefile'" '(1713 characters)'
  62. if test -f 'Makefile'
  63. then
  64.     echo shar: will not over-write existing file "'Makefile'"
  65. else
  66. cat << \SHAR_EOF > 'Makefile'
  67. # @(#)Makefile    2.1
  68.  
  69. # If you want something other than Eastern United States time used on your
  70. # system, change the line below (after finding the zone you want in the
  71. # time zone files, or adding it to a time zone file).
  72. # Alternately, if you discover you've got the wrong time zone, you can just
  73. #    tzcomp -l rightzone
  74.  
  75. LOCALTIME=    Eastern
  76.  
  77. # Use an absolute path name for TZDIR unless you're just testing the software.
  78.  
  79. TZDIR=        /etc/tzdir
  80.  
  81. # LINTFLAGS is set for 4.1bsd systems.  If you're using System V, you'll want
  82. # to comment out the "LINTFLAGS=" line.
  83.  
  84. LINTFLAGS=    -phbaaxc
  85.  
  86. DEBUG=
  87. LFLAGS=
  88. CFLAGS=        $(DEBUG) -O -DOBJECTID -DTZDIR=\"$(TZDIR)\"
  89.  
  90. TZCSRCS=    tzcomp.c scheck.c strchr.c mkdir.c
  91. TZCOBJS=    tzcomp.o scheck.o strchr.o mkdir.o
  92. TZDSRCS=    tzdump.c settz.c
  93. TZDOBJS=    tzdump.o settz.o
  94. DOCS=        README Makefile settz.3 tzfile.5 tzcomp.8
  95. SOURCES=    tzfile.h $(TZCSRCS) $(TZDSRCS) years.sh
  96. DATA=        asia australasia europe etcetera northamerica pacificnew
  97. ENCHILADA=    $(DOCS) $(SOURCES) $(DATA)
  98.  
  99. all:    REDID_BINARIES tzdump
  100.  
  101. REDID_BINARIES:    $(TZDIR) tzcomp $(DATA) years
  102.     tzcomp -l $(LOCALTIME) -d $(TZDIR) $(DATA)
  103.     cp /dev/null $@
  104.  
  105. tzdump:    $(TZDOBJS)
  106.     $(CC) $(LFLAGS) $(TZDOBJS) -o $@
  107.  
  108. tzcomp:    $(TZCOBJS)
  109.     $(CC) $(LFLAGS) $(TZCOBJS) -o $@
  110.  
  111. $(TZDIR):
  112.     mkdir $@
  113.  
  114. years:    years.sh
  115.     rm -f $@
  116.     cp $? $@
  117.     chmod 555 $@
  118.  
  119. BUNDLE1:    $(DOCS)
  120.     bundle $(DOCS) > BUNDLE1
  121.  
  122. BUNDLE2:    $(SOURCES)
  123.     bundle $(SOURCES) > BUNDLE2
  124.  
  125. BUNDLE3:    $(DATA)
  126.     bundle $(DATA) > BUNDLE3
  127.  
  128. $(ENCHILADA):
  129.     sccs get $(REL) $(REV) $@
  130.  
  131. sure:    $(TZCSRCS) $(TZDSRCS)
  132.     lint $(LINTFLAGS) $(TZCSRCS)
  133.     lint $(LINTFLAGS) $(TZDSRCS)
  134.  
  135. clean:
  136.     rm -f core *.o *.out REDID_BINARIES years tzdump tzcomp BUNDLE \#*
  137.  
  138. CLEAN:    clean
  139.     sccs clean
  140.  
  141. tzdump.o tzcomp.o settz.o:    tzfile.h
  142. SHAR_EOF
  143. if test 1713 -ne "`wc -c < 'Makefile'`"
  144. then
  145.     echo shar: error transmitting "'Makefile'" '(should have been 1713 characters)'
  146. fi
  147. fi
  148. echo shar: extracting "'settz.3'" '(1606 characters)'
  149. if test -f 'settz.3'
  150. then
  151.     echo shar: will not over-write existing file "'settz.3'"
  152. else
  153. cat << \SHAR_EOF > 'settz.3'
  154. .TH SETTZ 3 
  155. .SH NAME
  156. settz, newctime, newlocaltime \- convert date and time to ASCII
  157. .SH SYNOPSIS
  158. .nf
  159. .B settz(zonename)
  160. .B char *zonename;
  161. .PP
  162. .B char *newctime(clock)
  163. .B long *clock;
  164. .PP
  165. .B
  166. #include "time.h"
  167. .PP
  168. .B struct tm *newlocaltime(clock)
  169. .B long *clock;
  170. .PP
  171. .B char *tz_abbr;
  172. .SH DESCRIPTION
  173. .I Settz
  174. sets time conversion information used by
  175. .IR newlocaltime .
  176. If
  177. .I zonename
  178. begins with a slash,
  179. it is used as the absolute pathname of the
  180. .IR tzfile (5)-format
  181. file from which to read the time conversion information;
  182. if
  183. .I zonename
  184. begins with some other character,
  185. it is used as a pathname relative to the standard time conversion information
  186. directory.  A call of the form
  187. .ti +.5i
  188. .B
  189. settz("")
  190. .br
  191. causes built-in information about GMT to be used; a call of the form
  192. .ti +.5i
  193. .B
  194. settz((char *) 0)
  195. .br
  196. is treated as if it were a call of the form
  197. .ti +.5i
  198. .B
  199. settz("localtime")
  200. .PP
  201. .I Newlocaltime
  202. has the same argument and return value as
  203. .IR localtime .
  204. If
  205. .I newlocaltime
  206. is called before
  207. .I settz
  208. is called,
  209. .I newlocaltime
  210. calls
  211. .I settz
  212. with the value returned by
  213. .B
  214. getenv("TZ").
  215. .I Newlocaltime
  216. sets
  217. tz_abbr
  218. to a pointer to an 
  219. ASCII string that's the time zone abbreviation to be used with
  220. .IR newlocaltime 's
  221. return value.
  222. .PP
  223. .I Newctime
  224. returns
  225. .IR "asctime(newlocaltime(*clock))" .
  226. .SH DIAGNOSTICS
  227. .I Settz
  228. returns zero if all seems well; it returns negative one otherwise
  229. (and sets things up so that its built-in information about GMT is used).
  230. .SH FILES
  231. /etc/tzdir    standard time conversion information directory
  232. .SH "SEE ALSO"
  233. ctime(3), getenv(3), tzfile(5)
  234. .. @(#)settz.3    2.1
  235. SHAR_EOF
  236. if test 1606 -ne "`wc -c < 'settz.3'`"
  237. then
  238.     echo shar: error transmitting "'settz.3'" '(should have been 1606 characters)'
  239. fi
  240. fi
  241. echo shar: extracting "'tzfile.5'" '(2100 characters)'
  242. if test -f 'tzfile.5'
  243. then
  244.     echo shar: will not over-write existing file "'tzfile.5'"
  245. else
  246. cat << \SHAR_EOF > 'tzfile.5'
  247. .TH TZFILE 5
  248. .SH NAME
  249. tzfile \- time zone information
  250. .SH SYNOPSIS
  251. .B
  252. #include "tzfile.h"
  253. .SH DESCRIPTION
  254. The time zone information files used by
  255. .IR settz (3)
  256. and
  257. .IR newlocaltime (3)
  258. begin with a
  259. .I tzinfo
  260. structure (as defined in the include file
  261. .B 
  262. "tzfile.h"\c
  263. ):
  264. .sp
  265. .nf
  266. .in +.5i
  267. .ta .5i +\w'unsigned short  'u
  268. struct tzhead {
  269.     char    tzh_reserved[14];
  270.     unsigned short    tzh_timecnt;
  271.     unsigned short    tzh_typecnt;
  272.     unsigned short    tzh_charcnt;
  273. };
  274. .in -.5i
  275. .fi
  276. .PP
  277. The
  278. .B tzh_reserved
  279. element is currently unused.
  280. The
  281. .B tzh_timecnt
  282. element gives the number of "transition times" for which data is stored
  283. in the file;
  284. the
  285. .B tzh_typecnt
  286. (which must not be zero)
  287. element gives the number of "local time types" for which data is stored
  288. in the file;
  289. and the
  290. .B tzh_charcnt
  291. element gives the number of characters of "time zone abbreviation strings"
  292. stored in the file.
  293. .PP
  294. The above header is followed by
  295. .B tzh_timecnt
  296. values of type
  297. .BR long ,
  298. sorted in ascending order;
  299. each is used as a transition time (as returned by
  300. .IR time (2))
  301. at which the rules for computing local time change.
  302. Next come
  303. .B tzh_timecnt
  304. values of type
  305. .BR "unsigned char" ;
  306. each one tells which of the different types of "local time" described in the
  307. file is associated with the same-indexed transition time.
  308. These values serve as indices into an array of
  309. .B ttinfo
  310. structures that appears next in the file; 
  311. these structures are defined as follows:
  312. .in +.5i
  313. .sp
  314. .nf
  315. .ta .5i +\w'unsigned short  'u
  316. struct ttinfo {    
  317.     long    tt_gmtoff;
  318.     int    tt_isdst;
  319.     unsigned int    tt_abbrind;
  320. };
  321. .in -.5i
  322. .fi
  323. .sp
  324. In each structure,
  325. .B tt_gmtoff
  326. gives the number of seconds to be added to GMT,
  327. .B
  328. tt_isdst
  329. tells whether
  330. .B
  331. tm_isdst
  332. should be set by
  333. .IR newlocaltime (3),
  334. and
  335. .B tt_abbrind
  336. serves as an index into the array of time zone abbreviation chaaracters
  337. that follow the
  338. .B ttinfo
  339. structure(s) in the file.
  340. .PP
  341. .I Newlocaltime
  342. uses the first
  343. .B ttinfo
  344. structure in the file
  345. if either
  346. .B tzh_timecnt
  347. is zero or
  348. .IR newlocaltime 's
  349. argument is less than
  350. the first transition time recorded in the file.
  351. .SH SEE ALSO
  352. settz(3)
  353. .. @(#)tzfile.5    2.1
  354. SHAR_EOF
  355. if test 2100 -ne "`wc -c < 'tzfile.5'`"
  356. then
  357.     echo shar: error transmitting "'tzfile.5'" '(should have been 2100 characters)'
  358. fi
  359. fi
  360. echo shar: extracting "'tzcomp.8'" '(5479 characters)'
  361. if test -f 'tzcomp.8'
  362. then
  363.     echo shar: will not over-write existing file "'tzcomp.8'"
  364. else
  365. cat << \SHAR_EOF > 'tzcomp.8'
  366. .TH TZCOMP 8
  367. .SH NAME
  368. tzcomp \- time zone compiler
  369. .SH SYNOPSIS
  370. .B tzcomp
  371. [
  372. .B \-d
  373. directory ] [
  374. .B \-l
  375. localtime ] [ filename ... ]
  376. .SH DESCRIPTION
  377. .I Tzcomp
  378. reads text from the file(s) named on the command line
  379. and creates the time conversion information files specified in this input.
  380. If a
  381. .I filename
  382. is
  383. .BR ` - ',
  384. the standard input is read.
  385. .PP
  386. These options are available:
  387. .TP
  388. .BI "\-d " directory
  389. Create time conversion information files in the named directory rather than
  390. in the standard directory named below.
  391. .TP
  392. .BI "\-l " localtime
  393. Use the given time zone as local time.
  394. .PP
  395. Input lines are made up of fields.
  396. Fields are separated from one another by any number of white space characters.
  397. Leading and trailing white space on input lines is ignored.
  398. An unquoted sharp character (#) in the input introduces a comment which extends
  399. to the end of the line the sharp character appears on.
  400. White space characters and sharp characters may be enclosed in double quotes
  401. (") if they're to be used as part of a field.
  402. Any line which is blank (after comment stripping) is ignored.
  403. Non-blank lines are expected to be of one of three
  404. types:  rule lines, zone lines, and link lines.
  405. .PP
  406. A rule line has the form
  407. .nf
  408. .B
  409. .ti +.5i
  410. .ta \w'Rule 'u +\w'MostNA 'u +\w'FROM 'u +\w'1973 'u +\w'TYPE 'u +\w'Apr 'u +\w'lastSun 'u +\w'2:00 'u +\w'SAVE 'u
  411. .sp
  412. Rule    NAME    FROM    TO    TYPE    IN    ON    AT    SAVE    LETTER/S
  413. .sp
  414. For example:
  415. .ti +.5i
  416. .sp
  417. Rule    MostNA    1969    1973    -    Apr    lastSun    2:00    1:00    D
  418. .sp
  419. .fi
  420. The fields that make up a rule line are:
  421. .TP
  422. .B NAME
  423. Gives the (arbitrary) name of the set of rules this rule is part of.
  424. .TP
  425. .B FROM
  426. Gives the first year in which the rule applies.
  427. .TP
  428. .B TO
  429. Gives the last year in which the rule applies.
  430. The word
  431. .RB ` only '
  432. may be used to repeat the value of the
  433. .B
  434. FROM
  435. field.
  436. .TP
  437. .B TYPE
  438. Gives the type of year in which the year applies.  If
  439. .B TYPE
  440. is
  441. .B
  442. "-"
  443. then the rule applies in all years between
  444. .B FROM
  445. and
  446. .B TO
  447. inclusive.
  448. If
  449. .B TYPE
  450. is something else, then the command
  451. .B
  452. .ti +.5i
  453. years from to type
  454. .br
  455. is executed with arguments
  456. .IR from ,
  457. .IR to ,
  458. and
  459. .I type
  460. taken from the rule line; the rule applies only in those years
  461. printed by the
  462. .I years
  463. command.
  464.  
  465. The distributed
  466. .I years
  467. command is a shell script that handles year types
  468. .B uspres
  469. (United States presidential election years)
  470. and
  471. .B nonpres
  472. (all other years);
  473. other year types may be added by changing the script.
  474. .TP
  475. .B IN
  476. Names the month in which the rule takes effect.  Month names may be
  477. abbreviated.
  478. .TP
  479. .B ON
  480. Gives the day on which the rule takes effect.
  481. Recognized forms include:
  482. .nf
  483. .in +.5i
  484. .sp
  485. .ta \w'lastSun  'u
  486. 5    the fifth of the month
  487. lastSun    the last Sunday in the month
  488. lastMon    the last Monday in the month
  489. Sun>=8    first Sunday on or after the eighth
  490. Sun<=25    last Sunday on or before the 25th
  491. .fi
  492. .in -.5i
  493. .sp
  494. Names of days of the week may be abbreviated or spelled out in full.
  495. Note that there must be no spaces within the
  496. .B ON
  497. field.
  498. .TP
  499. .B AT
  500. Gives the time of day at which the rule takes affect.
  501. Recognized forms include:
  502. .nf
  503. .in +.5i
  504. .sp
  505. .ta \w'1:28:13  'u
  506. 2    time in hours
  507. 2:00    time in hours and minutes
  508. 15:00    24-hour format time (for times after noon)
  509. 1:28:14    time in hours, minutes, and seconds
  510. .fi
  511. .in -.5i
  512. .sp
  513. Any of these forms may be followed by the letter 'w' if the given time is
  514. local "wall clock" time or 's' if the given time is local "standard" time;
  515. in the absence of 'w' or 's', wall clock time is assumed.
  516. .TP
  517. .B SAVE
  518. Gives the amount of time to be added to local standard time when the rule is in
  519. effect (although, of course, the 'w' and 's' suffixes are not used).
  520. This field has the same format as the
  521. .B AT
  522. field.
  523. .TP
  524. .B LETTER/S
  525. Gives the "variable part" (for example, the 'S' or 'D' in "EST" or "EDT")
  526. of time zone abbreviations to be used when this rule is in effect.
  527. If this field is
  528. .B
  529. "-",
  530. the variable part is null.
  531. .PP
  532. A zone line has the form
  533. .sp
  534. .nf
  535. .ti +.5i
  536. .ta \w'Zone 'u +\w'Eastern 'u +\w'GMTOFF 'u +\w'MostNA 'u
  537. Zone    NAME    GMTOFF    RULES    FORMAT
  538. .sp
  539. For example:
  540. .sp
  541. .ti +.5i
  542. Zone    Eastern    -5:00    MostNA    E%sT
  543. .sp
  544. .fi
  545. The fields that make up a zone line are:
  546. .TP
  547. .B NAME
  548. The name of the time zone.
  549. This is the name used in creating the time conversion information file for the
  550. zone.
  551. .TP
  552. .B GMTOFF
  553. The amount of time to add to GMT to get standard time in this zone.
  554. This field has the same format as the
  555. .B AT
  556. and
  557. .B SAVE
  558. fields of rule lines;
  559. begin the field with a minus sign if time must be subtracted from GMT.
  560. .TP
  561. .B RULES
  562. The name of the rule(s) that apply in the time zone.
  563. If this field is
  564. .B
  565. "-"
  566. then standard time always applies in the time zone.
  567. .TP
  568. .B FORMAT
  569. The format for time zone abbreviations in this time zone.
  570. The pair of characters
  571. .B
  572. "%s"
  573. is used to show where the "variable part" of the time zone abbreviation goes.
  574. .PP
  575. A link line has the form
  576. .sp
  577. .nf
  578. .ti +.5i
  579. .ta \w'Link 'u +\w'LINK-FROM 'u
  580. Link    LINK-FROM    LINK-TO
  581. .sp
  582. For example:
  583. .sp
  584. .ti +.5i
  585. Link    Eastern        EST5EDT
  586. .sp
  587. .fi
  588. The
  589. .B LINK-FROM
  590. field should appear as the
  591. .B NAME
  592. field in some zone line;
  593. the
  594. .B LINK-TO
  595. field is used as an alternate name for that zone.
  596. .PP
  597. Lines may appear in any order in the input.
  598. .SH NOTE
  599. For areas with more than two types of local time,
  600. you may get to use local standard time in "AT" field of the earliest
  601. transition time's rule to ensure that
  602. the earliest transition time recorded in the compiled file is correct.
  603. .SH FILES
  604. /etc/tzdir    standard directory used for created files
  605. .SH "SEE ALSO"
  606. settz(3), tzfile(5)
  607. .. @(#)tzcomp.8    2.1
  608. SHAR_EOF
  609. if test 5479 -ne "`wc -c < 'tzcomp.8'`"
  610. then
  611.     echo shar: error transmitting "'tzcomp.8'" '(should have been 5479 characters)'
  612. fi
  613. fi
  614. echo shar: extracting "'tzfile.h'" '(1409 characters)'
  615. if test -f 'tzfile.h'
  616. then
  617.     echo shar: will not over-write existing file "'tzfile.h'"
  618. else
  619. cat << \SHAR_EOF > 'tzfile.h'
  620. /* @(#)tzfile.h    2.1 */
  621.  
  622. /*
  623. ** Information about time zone files.
  624. */
  625.  
  626. #ifndef TZDIR
  627. #define TZDIR        "/etc/tzdir"    /* Time zone object file directory */
  628. #endif
  629.  
  630. #ifndef TZDEFAULT
  631. #define TZDEFAULT    "localtime"
  632. #endif
  633.  
  634. struct ttinfo {                /* time type information */
  635.     long        tt_gmtoff;    /* GMT offset in seconds */
  636.     int        tt_isdst;    /* used to set tm_isdst */
  637.     unsigned int    tt_abbrind;    /* abbreviation list index */
  638. };
  639.  
  640. /*
  641. ** Each file begins with. . .
  642. */
  643.  
  644. struct tzhead {
  645.     char        tzh_reserved[14];    /* reserved for future use */
  646.     unsigned short    tzh_timecnt;        /* number of transition times */
  647.     unsigned short    tzh_typecnt;        /* number of local time types */
  648.     unsigned short    tzh_charcnt;        /* number of abbr. chars */
  649. };
  650.  
  651. /*
  652. ** . . .followed by. . .
  653. **
  654. **    tzh_timecnt (long)s        transition times as returned by time(2)
  655. **    tzh_timecnt (unsigned char)s    types of local time starting at above
  656. **    tzh_typecnt (struct ttinfo)s    information for each time type
  657. **    tzh_charcnt (char)s        '\0'-terminated zone abbreviaton strings
  658. */
  659.  
  660. /*
  661. ** In the current implementation, "settz()" refuses to deal with files that
  662. ** exceed any of the limits below.
  663. */
  664.  
  665. #ifndef TZ_MAX_TIMES
  666. #define TZ_MAX_TIMES    170    /* Maximum number of transition times */
  667. #endif
  668.  
  669. #ifndef TZ_MAX_TYPES
  670. #define TZ_MAX_TYPES    10    /* Maximum number of local time types */
  671. #endif
  672.  
  673. #ifndef TZ_MAX_CHARS
  674. #define TZ_MAX_CHARS    50    /* Maximum number of abbreviation characters */
  675. #endif
  676. SHAR_EOF
  677. if test 1409 -ne "`wc -c < 'tzfile.h'`"
  678. then
  679.     echo shar: error transmitting "'tzfile.h'" '(should have been 1409 characters)'
  680. fi
  681. fi
  682. echo shar: extracting "'tzcomp.c'" '(24558 characters)'
  683. if test -f 'tzcomp.c'
  684. then
  685.     echo shar: will not over-write existing file "'tzcomp.c'"
  686. else
  687. cat << \SHAR_EOF > 'tzcomp.c'
  688. #
  689.  
  690. #include "stdio.h"
  691.  
  692. #ifdef OBJECTID
  693. static char    sccsid[] = "@(#)tzcomp.c    2.1";
  694. #endif
  695.  
  696. #include "tzfile.h"
  697. #include "ctype.h"
  698.  
  699. #ifndef alloc_t
  700. #define alloc_t    unsigned
  701. #endif
  702.  
  703. #ifndef MAL
  704. #define MAL    NULL
  705. #endif
  706.  
  707. #ifndef BUFSIZ
  708. #define BUFSIZ    1024
  709. #endif
  710.  
  711. #ifndef TRUE
  712. #define TRUE    1
  713. #define FALSE    0
  714. #endif
  715.  
  716. #ifdef lint
  717. #define scheck(string, format)    (format)
  718. #endif
  719. #ifndef lint
  720. extern char *    scheck();
  721. #endif
  722.  
  723. extern char *    calloc();
  724. extern char *    malloc();
  725. extern char *    optarg;
  726. extern int    optind;
  727. extern FILE *    popen();
  728. extern char *    realloc();
  729. extern char *    sprintf();
  730. extern char *    strcat();
  731. extern char *    strchr();
  732. extern char *    strcpy();
  733.  
  734. static int    errors;
  735. static char *    filename;
  736. static char **    getfields();
  737. static int    linenum;
  738. static char *    progname;
  739. static long    rpytime();
  740. static long    tadd();
  741.  
  742. #define    SECS_PER_MIN    60L
  743. #define MINS_PER_HOUR    60L
  744. #define HOURS_PER_DAY    24L
  745. #define DAYS_PER_YEAR    365L    /* Except in leap years */
  746. #define    SECS_PER_HOUR    (SECS_PER_MIN * MINS_PER_HOUR)
  747. #define SECS_PER_DAY    (SECS_PER_HOUR * HOURS_PER_DAY)
  748. #define SECS_PER_YEAR    (SECS_PER_DAY * DAYS_PER_YEAR)
  749.  
  750. #define EPOCH_YEAR    1970
  751. #define EPOCH_WDAY    TM_THURSDAY
  752.  
  753. /*
  754. ** Values a la localtime(3)
  755. */
  756.  
  757. #define TM_JANUARY    0
  758. #define TM_FEBRUARY    1
  759. #define TM_MARCH    2
  760. #define TM_APRIL    3
  761. #define TM_MAY        4
  762. #define TM_JUNE        5
  763. #define TM_JULY        6
  764. #define TM_AUGUST    7
  765. #define TM_SEPTEMBER    8
  766. #define TM_OCTOBER    9
  767. #define TM_NOVEMBER    10
  768. #define TM_DECEMBER    11
  769.  
  770. #define TM_SUNDAY    0
  771. #define TM_MONDAY    1
  772. #define TM_TUESDAY    2
  773. #define TM_WEDNESDAY    3
  774. #define TM_THURSDAY    4
  775. #define TM_FRIDAY    5
  776. #define TM_SATURDAY    6
  777.  
  778. /*
  779. ** Line codes.
  780. */
  781.  
  782. #define LC_RULE        0
  783. #define LC_ZONE        1
  784. #define LC_LINK        2
  785.  
  786. /*
  787. ** Which fields are which on a Zone line.
  788. */
  789.  
  790. #define ZF_NAME        1
  791. #define ZF_GMTOFF    2
  792. #define ZF_RULE        3
  793. #define ZF_FORMAT    4
  794. #define ZONE_FIELDS    5
  795.  
  796. /*
  797. ** Which files are which on a Rule line.
  798. */
  799.  
  800. #define    RF_NAME        1
  801. #define RF_LOYEAR    2
  802. #define RF_HIYEAR    3
  803. #define RF_COMMAND    4
  804. #define RF_MONTH    5
  805. #define RF_DAY        6
  806. #define RF_TOD        7
  807. #define RF_STDOFF    8
  808. #define RF_ABBRVAR    9
  809. #define RULE_FIELDS    10
  810.  
  811. /*
  812. ** Which fields are which on a Link line.
  813. */
  814.  
  815. #define LF_FROM        1
  816. #define LF_TO        2
  817. #define LINK_FIELDS    3
  818.  
  819. struct rule {
  820.     char *    r_filename;
  821.     int    r_linenum;
  822.     char *    r_name;
  823.  
  824.     long    r_loyear;    /* for example, 1986 */
  825.     long    r_hiyear;    /* for example, 1986 */
  826.     char *    r_yrtype;
  827.  
  828.     long    r_month;    /* 0..11 */
  829.  
  830.     int    r_dycode;    /* see below */
  831.     long    r_dayofmonth;
  832.     long    r_wday;
  833.  
  834.     long    r_tod;        /* time from midnight */
  835.     int    r_todisstd;    /* above is standard time if TRUE */
  836.                 /* above is wall clock time if FALSE */
  837.     long    r_stdoff;    /* offset from standard time */
  838.     char *    r_abbrvar;    /* variable part of time zone abbreviation */
  839.  
  840.     int    r_type;    /* used when creating output files */
  841. };
  842.  
  843. /*
  844. **    r_dycode        r_dayofmonth    r_wday
  845. */
  846. #define DC_DOM        0    /* 1..31 */    /* unused */
  847. #define DC_DOWGEQ    1    /* 1..31 */    /* 0..6 (Sun..Sat) */
  848. #define DC_DOWLEQ    2    /* 1..31 */    /* 0..6 (Sun..Sat) */
  849.  
  850. static struct rule *    rules;
  851. static int        nrules;    /* number of rules */
  852.  
  853. struct zone {
  854.     char *        z_filename;
  855.     int        z_linenum;
  856.  
  857.     char *        z_name;
  858.     long        z_gmtoff;
  859.     char *        z_rule;
  860.     char *        z_format;
  861.  
  862.     struct rule *    z_rules;
  863.     int        z_nrules;
  864. };
  865.  
  866. static struct zone *    zones;
  867. static int        nzones;    /* number of zones */
  868.  
  869. struct link {
  870.     char *        l_filename;
  871.     int        l_linenum;
  872.     char *        l_from;
  873.     char *        l_to;
  874. };
  875.  
  876. static struct link *    links;
  877. static int        nlinks;
  878.  
  879. struct lookup {
  880.     char *        l_word;
  881.     long        l_value;
  882. };
  883.  
  884. static struct lookup *    byword();
  885.  
  886. static struct lookup    line_codes[] = {
  887.     "Rule",        LC_RULE,
  888.     "Zone",        LC_ZONE,
  889.     "Link",        LC_LINK,
  890.     NULL,        0
  891. };
  892.  
  893. static struct lookup    mon_names[] = {
  894.     "January",    TM_JANUARY,
  895.     "February",    TM_FEBRUARY,
  896.     "March",    TM_MARCH,
  897.     "April",    TM_APRIL,
  898.     "May",        TM_MAY,
  899.     "June",        TM_JUNE,
  900.     "July",        TM_JULY,
  901.     "August",    TM_AUGUST,
  902.     "September",    TM_SEPTEMBER,
  903.     "October",    TM_OCTOBER,
  904.     "November",    TM_NOVEMBER,
  905.     "December",    TM_DECEMBER,
  906.     NULL,        0
  907. };
  908.  
  909. static struct lookup    wday_names[] = {
  910.     "Sunday",    TM_SUNDAY,
  911.     "Monday",    TM_MONDAY,
  912.     "Tuesday",    TM_TUESDAY,
  913.     "Wednesday",    TM_WEDNESDAY,
  914.     "Thursday",    TM_THURSDAY,
  915.     "Friday",    TM_FRIDAY,
  916.     "Saturday",    TM_SATURDAY,
  917.     NULL,        0
  918. };
  919.  
  920. static struct lookup    lasts[] = {
  921.     "last-Sunday",        TM_SUNDAY,
  922.     "last-Monday",        TM_MONDAY,
  923.     "last-Tuesday",        TM_TUESDAY,
  924.     "last-Wednesday",    TM_WEDNESDAY,
  925.     "last-Thursday",    TM_THURSDAY,
  926.     "last-Friday",        TM_FRIDAY,
  927.     "last-Saturday",    TM_SATURDAY,
  928.     NULL,            0
  929. };
  930.  
  931. static long    mon_lengths[] = {    /* ". . .knuckles are 31. . ." */
  932.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  933. };
  934.  
  935. static struct tzhead    h;
  936. static long        ats[TZ_MAX_TIMES];
  937. static unsigned char    types[TZ_MAX_TIMES];
  938. static struct ttinfo    ttis[TZ_MAX_TYPES];
  939. static char        chars[TZ_MAX_CHARS];
  940.  
  941. /*
  942. ** Exits.
  943. */
  944.  
  945. static
  946. tameexit()
  947. {
  948.     exit(0);
  949. }
  950.  
  951. static
  952. wild2exit(part1, part2)
  953. char *    part1;
  954. char *    part2;
  955. {
  956.     register char *    between;
  957.  
  958.     if (part1 == NULL)
  959.         part1 = "";
  960.     if (part2 == NULL)
  961.         part2 = "";
  962.     between = (*part1 == '\0' || *part2 == '\0') ? "" : " ";
  963.     (void) fprintf(stderr, "%s: wild %s%s%s\n",
  964.         progname, part1, between, part2);
  965.     exit(1);
  966. }
  967.  
  968. static
  969. wildexit(string)
  970. char *    string;
  971. {
  972.     wild2exit(string, (char *) NULL);
  973. }
  974.  
  975. static
  976. wildrexit(string)
  977. char *    string;
  978. {
  979.     wild2exit("result from", string);
  980. }
  981.  
  982. /*
  983. ** Memory allocation.
  984. */
  985.  
  986. static char *
  987. emalloc(size)
  988. {
  989.     register char *    cp;
  990.  
  991.     if ((cp = malloc((alloc_t) size)) == NULL || cp == MAL)
  992.         wildrexit("malloc");
  993.     return cp;
  994. }
  995.  
  996. static char *
  997. erealloc(ptr, size)
  998. char *    ptr;
  999. {
  1000.     register char *    cp;
  1001.  
  1002.     if ((cp = realloc(ptr, (alloc_t) size)) == NULL)
  1003.         wildrexit("realloc");
  1004.     return cp;
  1005. }
  1006.  
  1007. static char *
  1008. eallocpy(old)
  1009. char *    old;
  1010. {
  1011.     register char *    new;
  1012.  
  1013.     if (old == NULL)
  1014.         old = "";
  1015.     new = emalloc(strlen(old) + 1);
  1016.     (void) strcpy(new, old);
  1017.     return new;
  1018. }
  1019.  
  1020. static
  1021. usage()
  1022. {
  1023.     (void) fprintf(stderr,
  1024.     "%s: usage is %s [ -l localtime ] [ -d directory ] [ filename ... ]\n",
  1025.         progname, progname);
  1026.     exit(1);
  1027. }
  1028.  
  1029. static char *    localtime = NULL;
  1030. static char *    directory = NULL;
  1031.  
  1032. main(argc, argv)
  1033. int    argc;
  1034. char *    argv[];
  1035. {
  1036.     register int    i;
  1037.     register int    c;
  1038.  
  1039.     progname = argv[0];
  1040.     while ((c = getopt(argc, argv, "d:l:")) != EOF)
  1041.         switch (c) {
  1042.             default:
  1043.                 usage();
  1044.             case 'd':
  1045.                 if (directory == NULL)
  1046.                     directory = optarg;
  1047.                 else    wildexit("multiple command line -d's");
  1048.                 break;
  1049.             case 'l':
  1050.                 if (localtime == NULL)
  1051.                     localtime = optarg;
  1052.                 else    wildexit("multiple command line -l's");
  1053.         }
  1054.     if (directory == NULL)
  1055.         directory = TZDIR;
  1056.     if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
  1057.         usage();    /* usage message by request */
  1058.     zones = (struct zone *) emalloc(0);
  1059.     rules = (struct rule *) emalloc(0);
  1060.     links = (struct link *) emalloc(0);
  1061.     for (i = optind; i < argc; ++i)
  1062.         infile(argv[i]);
  1063.     if (errors)
  1064.         wildexit("input data");
  1065.     associate();
  1066.     for (i = 0; i < nzones; ++i)
  1067.         outzone(&zones[i]);
  1068.     /*
  1069.     ** We'll take the easy way out on this last part.
  1070.     */
  1071.     if (chdir(directory) != 0)
  1072.         wild2exit("result from chdir to", directory);
  1073.     for (i = 0; i < nlinks; ++i) {
  1074.         (void) unlink(links[i].l_to);
  1075.         if (link(links[i].l_from, links[i].l_to) != 0)
  1076.             wild2exit("result creating", links[i].l_to);
  1077.     }
  1078.     if (localtime != NULL) {
  1079.         (void) unlink(TZDEFAULT);
  1080.         if (link(localtime, TZDEFAULT) != 0)
  1081.             wild2exit("result creating", TZDEFAULT);
  1082.     }
  1083.     tameexit();
  1084. }
  1085.  
  1086. /*
  1087. ** Associate sets of rules with zones.
  1088. */
  1089.  
  1090. /*
  1091. ** Sort by rule name, and by magnitude of standard time offset for rules of
  1092. ** the same name.  The second sort gets standard time entries to the start
  1093. ** of the dsinfo table (and we want a standard time entry at the start of
  1094. ** the table, since the first entry gets used for times not covered by the
  1095. ** rules).
  1096. */
  1097.  
  1098. static
  1099. rcomp(cp1, cp2)
  1100. char *    cp1;
  1101. char *    cp2;
  1102. {
  1103.     register struct rule *    rp1;
  1104.     register struct rule *    rp2;
  1105.     register long        l1, l2;
  1106.     register int        diff;
  1107.  
  1108.     rp1 = (struct rule *) cp1;
  1109.     rp2 = (struct rule *) cp2;
  1110.     if ((diff = strcmp(rp1->r_name, rp2->r_name)) != 0)
  1111.         return diff;
  1112.     if ((l1 = rp1->r_stdoff) < 0)
  1113.         l1 = -l1;
  1114.     if ((l2 = rp2->r_stdoff) < 0)
  1115.         l2 = -l2;
  1116.     if (l1 > l2)
  1117.         return 1;
  1118.     else if (l1 < l2)
  1119.         return -1;
  1120.     else    return 0;
  1121. }
  1122.  
  1123. static
  1124. associate()
  1125. {
  1126.     register struct zone *    zp;
  1127.     register struct rule *    rp;
  1128.     register int        base, out;
  1129.     register int        i;
  1130.  
  1131.     if (nrules != 0)
  1132.         (void) qsort((char *) rules, nrules, sizeof *rules, rcomp);
  1133.     base = 0;
  1134.     for (i = 0; i < nzones; ++i) {
  1135.         zp = &zones[i];
  1136.         zp->z_rules = NULL;
  1137.         zp->z_nrules = 0;
  1138.     }
  1139.     while (base < nrules) {
  1140.         rp = &rules[base];
  1141.         for (out = base + 1; out < nrules; ++out)
  1142.             if (strcmp(rp->r_name, rules[out].r_name) != 0)
  1143.                 break;
  1144.         for (i = 0; i < nzones; ++i) {
  1145.             zp = &zones[i];
  1146.             if (strcmp(zp->z_rule, rp->r_name) != 0)
  1147.                 continue;
  1148.             zp->z_rules = rp;
  1149.             zp->z_nrules = out - base;
  1150.         }
  1151.         base = out;
  1152.     }
  1153.     for (i = 0; i < nzones; ++i) {
  1154.         zp = &zones[i];
  1155.         if (*zp->z_rule != '\0' && zp->z_nrules == 0) {
  1156.             filename = zp->z_filename;
  1157.             linenum = zp->z_linenum;
  1158.             error("unruly zone");
  1159.         }
  1160.     }
  1161.     if (errors)
  1162.         wildexit("unruly zone(s)");
  1163. }
  1164.  
  1165. static
  1166. error(string)
  1167. char *    string;
  1168. {
  1169.     (void) fprintf(stderr, "%s: file \"%s\", line %d: wild %s\n",
  1170.         progname, filename, linenum, string);
  1171.     ++errors;
  1172. }
  1173.  
  1174. static
  1175. infile(name)
  1176. char *    name;
  1177. {
  1178.     register FILE *            fp;
  1179.     register char **        fields;
  1180.     register char *            cp;
  1181.     register struct lookup *    lp;
  1182.     register int            nfields;
  1183.     char                buf[BUFSIZ];
  1184.  
  1185.     if (strcmp(name, "-") == 0) {
  1186.         name = "standard input";
  1187.         fp = stdin;
  1188.     } else if ((fp = fopen(name, "r")) == NULL)
  1189.         wild2exit("result opening", name);
  1190.     filename = eallocpy(name);
  1191.     for (linenum = 1; ; ++linenum) {
  1192.         if (fgets(buf, sizeof buf, fp) != buf)
  1193.             break;
  1194.         cp = strchr(buf, '\n');
  1195.         if (cp == NULL) {
  1196.             error("long line");
  1197.             wildexit("input data");
  1198.         }
  1199.         *cp = '\0';
  1200.         if ((fields = getfields(buf)) == NULL)
  1201.             wildrexit("getfields");
  1202.         nfields = 0;
  1203.         while (fields[nfields] != NULL) {
  1204.             if (ciequal(fields[nfields], "-"))
  1205.                 fields[nfields] = "";
  1206.             ++nfields;
  1207.         }
  1208.         if (nfields > 0)    /* non-blank line */
  1209.             if ((lp = byword(fields[0], line_codes)) == NULL)
  1210.                 error("input line of unknown type");
  1211.             else switch (lp->l_value) {
  1212.                 case LC_RULE:
  1213.                     inrule(fields, nfields);
  1214.                     break;
  1215.                 case LC_ZONE:
  1216.                     inzone(fields, nfields);
  1217.                     break;
  1218.                 case LC_LINK:
  1219.                     inlink(fields, nfields);
  1220.                     break;
  1221.                 default:    /* "cannot happen" */
  1222.                     wildrexit("lookup");
  1223.             }
  1224.         free((char *) fields);
  1225.     }
  1226.     if (ferror(fp))
  1227.         wild2exit("result reading", filename);
  1228.     if (fp != stdin && fclose(fp))
  1229.         wild2exit("result closing", filename);
  1230. }
  1231.  
  1232. /*
  1233. ** Convert a string of one of the forms
  1234. **    h    -h     hh:mm    -hh:mm    hh:mm:ss    -hh:mm:ss
  1235. ** into a number of seconds. 
  1236. ** Call error with errstring and return zero on errors.
  1237. */
  1238.  
  1239. static long
  1240. getoff(string, errstring)
  1241. char *    string;
  1242. char *    errstring;
  1243. {
  1244.     long    hh, mm, ss, sign;
  1245.  
  1246.     if (*string == '-') {
  1247.         sign = -1;
  1248.         ++string;
  1249.     } else    sign = 1;
  1250.     if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
  1251.         mm = ss = 0;
  1252.     else if (sscanf(string, scheck(string, "%ld:%ld"), &hh, &mm) == 2)
  1253.         ss = 0;
  1254.     else if (sscanf(string, scheck(string, "%ld:%ld:%ld"),
  1255.         &hh, &mm, &ss) != 3) {
  1256.             error(errstring);
  1257.             return 0;
  1258.     }
  1259.     if (hh < 0 || hh >= HOURS_PER_DAY ||
  1260.         mm < 0 || mm >= MINS_PER_HOUR ||
  1261.         ss < 0 || ss >= SECS_PER_MIN) {
  1262.             error(errstring);
  1263.             return 0;
  1264.     }
  1265.     return (long) sign * (((hh * MINS_PER_HOUR) + mm) * SECS_PER_MIN + ss);
  1266. }
  1267.  
  1268. static
  1269. inrule(fields, nfields)
  1270. char **    fields;
  1271. {
  1272.     register struct lookup *    lp;
  1273.     register char *            cp;
  1274.     struct rule            r;
  1275.  
  1276.     if (nfields != RULE_FIELDS) {
  1277.         error("number of fields on Rule line");
  1278.         return;
  1279.     }
  1280.     r.r_filename = filename;
  1281.     r.r_linenum = linenum;
  1282.     if ((lp = byword(fields[RF_MONTH], mon_names)) == NULL) {
  1283.         error("month name");
  1284.         return;
  1285.     }
  1286.     r.r_month = lp->l_value;
  1287.     r.r_todisstd = FALSE;
  1288.     cp = fields[RF_TOD];
  1289.     if (strlen(cp) > 0) {
  1290.         cp += strlen(cp) - 1;
  1291.         switch (lowerit(*cp)) {
  1292.             case 's':
  1293.                 r.r_todisstd = TRUE;
  1294.                 *cp = '\0';
  1295.                 break;
  1296.             case 'w':
  1297.                 r.r_todisstd = FALSE;
  1298.                 *cp = '\0';
  1299.                 break;
  1300.         }
  1301.     }
  1302.     r.r_tod = getoff(fields[RF_TOD], "time of day");
  1303.     r.r_stdoff = getoff(fields[RF_STDOFF], "Standard Time offset");
  1304.     /*
  1305.     ** Year work.
  1306.     */
  1307.     cp = fields[RF_LOYEAR];
  1308.     if (sscanf(cp, scheck(cp, "%ld"), &r.r_loyear) != 1 ||
  1309.         r.r_loyear <= 0) {
  1310.             error("low year");
  1311.             return;
  1312.     }
  1313.     cp = fields[RF_HIYEAR];
  1314.     if (*cp == '\0' || ciequal(cp, "only"))
  1315.         r.r_hiyear = r.r_loyear;
  1316.     else if (sscanf(cp, scheck(cp, "%ld"), &r.r_hiyear) != 1 ||
  1317.         r.r_hiyear <= 0) {
  1318.             error("high year");
  1319.             return;
  1320.     }
  1321.     if (r.r_loyear > r.r_hiyear) {
  1322.         error("low year (greater than high year)");
  1323.         return;
  1324.     }
  1325.     if (*fields[RF_COMMAND] == '\0')
  1326.         r.r_yrtype = NULL;
  1327.     else {
  1328.         if (r.r_loyear == r.r_hiyear) {
  1329.             error("typed single year");
  1330.             return;
  1331.         }
  1332.         r.r_yrtype = eallocpy(fields[RF_COMMAND]);
  1333.     }
  1334.     /*
  1335.     ** Day work.
  1336.     ** Accept things such as:
  1337.     **    1
  1338.     **    last-Sunday
  1339.     **    Sun<=20
  1340.     **    Sun>=7
  1341.     */
  1342.     cp = fields[RF_DAY];
  1343.     if ((lp = byword(cp, lasts)) != NULL) {
  1344.         r.r_dycode = DC_DOWLEQ;
  1345.         r.r_wday = lp->l_value;
  1346.         r.r_dayofmonth = mon_lengths[r.r_month];
  1347.         if (r.r_month == TM_FEBRUARY)
  1348.             ++r.r_dayofmonth;
  1349.     } else {
  1350.         if ((cp = strchr(fields[RF_DAY], '<')) != 0)
  1351.             r.r_dycode = DC_DOWLEQ;
  1352.         else if ((cp = strchr(fields[RF_DAY], '>')) != 0)
  1353.             r.r_dycode = DC_DOWGEQ;
  1354.         else {
  1355.             cp = fields[RF_DAY];
  1356.             r.r_dycode = DC_DOM;
  1357.         }
  1358.         if (r.r_dycode != DC_DOM) {
  1359.             *cp++ = 0;
  1360.             if (*cp++ != '=') {
  1361.                 error("day of month");
  1362.                 return;
  1363.             }
  1364.             if ((lp = byword(fields[RF_DAY], wday_names)) == NULL) {
  1365.                 error("weekday name");
  1366.                 return;
  1367.             }
  1368.             r.r_wday = lp->l_value;
  1369.         }
  1370.         if (sscanf(cp, scheck(cp, "%ld"), &r.r_dayofmonth) != 1 ||
  1371.             r.r_dayofmonth <= 0 ||
  1372.             (r.r_dayofmonth > mon_lengths[r.r_month] &&
  1373.             r.r_month != TM_FEBRUARY && r.r_dayofmonth != 29)) {
  1374.                 error("day of month");
  1375.                 return;
  1376.         }
  1377.     }
  1378.     if (*fields[RF_NAME] == '\0') {
  1379.         error("nameless rule");
  1380.         return;
  1381.     }
  1382.     r.r_name = eallocpy(fields[RF_NAME]);
  1383.     r.r_abbrvar = eallocpy(fields[RF_ABBRVAR]);
  1384.     rules = (struct rule *) erealloc((char *) rules,
  1385.         (nrules + 1) * sizeof *rules);
  1386.     rules[nrules++] = r;
  1387. }
  1388.  
  1389. static
  1390. inzone(fields, nfields)
  1391. char **    fields;
  1392. {
  1393.     register char *    cp;
  1394.     register int    i;
  1395.     struct zone    z;
  1396.     char        buf[132];
  1397.  
  1398.     if (nfields != ZONE_FIELDS) {
  1399.         error("number of fields on Zone line");
  1400.         return;
  1401.     }
  1402.     z.z_filename = filename;
  1403.     z.z_linenum = linenum;
  1404.     for (i = 0; i < nzones; ++i)
  1405.         if (strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
  1406.             (void) sprintf(buf,
  1407.                 "duplicate zone name %s (file \"%s\", line %d)",
  1408.                 fields[ZF_NAME],
  1409.                 zones[i].z_filename,
  1410.                 zones[i].z_linenum);
  1411.             error(buf);
  1412.             return;
  1413.         }
  1414.     z.z_gmtoff = getoff(fields[ZF_GMTOFF], "GMT offset");
  1415.     if ((cp = strchr(fields[ZF_FORMAT], '%')) != 0) {
  1416.         if (*++cp != 's' || strchr(cp, '%') != 0) {
  1417.             error("format");
  1418.             return;
  1419.         }
  1420.     }
  1421.     z.z_name = eallocpy(fields[ZF_NAME]);
  1422.     z.z_rule = eallocpy(fields[ZF_RULE]);
  1423.     z.z_format = eallocpy(fields[ZF_FORMAT]);
  1424.     zones = (struct zone *) erealloc((char *) zones,
  1425.         (nzones + 1) * sizeof *zones);
  1426.     zones[nzones++] = z;
  1427. }
  1428.  
  1429. static
  1430. inlink(fields, nfields)
  1431. char **    fields;
  1432. {
  1433.     struct link    l;
  1434.  
  1435.     if (nfields != LINK_FIELDS) {
  1436.         error("number of fields on Link line");
  1437.         return;
  1438.     }
  1439.     if (*fields[LF_FROM] == '\0') {
  1440.         error("blank FROM field on Link line");
  1441.         return;
  1442.     }
  1443.     if (*fields[LF_TO] == '\0') {
  1444.         error("blank TO field on Link line");
  1445.         return;
  1446.     }
  1447.     l.l_filename = filename;
  1448.     l.l_linenum = linenum;
  1449.     l.l_from = eallocpy(fields[LF_FROM]);
  1450.     l.l_to = eallocpy(fields[LF_TO]);
  1451.     links = (struct link *) erealloc((char *) links,
  1452.         (nlinks + 1) * sizeof *links);
  1453.     links[nlinks++] = l;
  1454. }
  1455.  
  1456. static
  1457. writezone(name)
  1458. char *    name;
  1459. {
  1460.     register FILE *    fp;
  1461.     register int    i;
  1462.     char        fullname[BUFSIZ];
  1463.  
  1464.     if (strlen(directory) + 1 + strlen(name) >= BUFSIZ)
  1465.         wild2exit("long directory/file", filename);
  1466.     (void) sprintf(fullname, "%s/%s", directory, name);
  1467.     if ((fp = fopen(fullname, "w")) == NULL) {
  1468.         mkdirs(fullname);
  1469.         if ((fp = fopen(fullname, "w")) == NULL)
  1470.             wild2exit("result creating", fullname);
  1471.     }
  1472.     if (fwrite((char *) &h, sizeof h, 1, fp) != 1)
  1473.         goto wreck;
  1474.     if ((i = h.tzh_timecnt) != 0) {
  1475.         if (fwrite((char *) ats, sizeof ats[0], i, fp) != i)
  1476.             goto wreck;
  1477.         if (fwrite((char *) types, sizeof types[0], i, fp) != i)
  1478.             goto wreck;
  1479.     }
  1480.     if ((i = h.tzh_typecnt) != 0)
  1481.         if (fwrite((char *) ttis, sizeof ttis[0], i, fp) != i)
  1482.             goto wreck;
  1483.     if ((i = h.tzh_charcnt) != 0)
  1484.         if (fwrite(chars, sizeof chars[0], i, fp) != i)
  1485.             goto wreck;
  1486.     if (fclose(fp))
  1487.         wild2exit("result closing", fullname);
  1488.     return;
  1489. wreck:
  1490.     wild2exit("result writing", fullname);
  1491. }
  1492.  
  1493. struct temp {
  1494.     long        t_time;
  1495.     struct rule *    t_rp;
  1496. };
  1497.  
  1498. static struct temp    temps[TZ_MAX_TIMES];
  1499. static int        ntemps;
  1500.  
  1501. static
  1502. tcomp(cp1, cp2)
  1503. char *    cp1;
  1504. char *    cp2;
  1505. {
  1506.     register struct temp *    tp1;
  1507.     register struct temp *    tp2;
  1508.     register char *        cp;
  1509.     register long        diff;
  1510.  
  1511.     tp1 = (struct temp *) cp1;
  1512.     tp2 = (struct temp *) cp2;
  1513.     if (tp1->t_time > 0 && tp2->t_time <= 0)
  1514.         return 1;
  1515.     if (tp1->t_time <= 0 && tp2->t_time > 0)
  1516.         return -1;
  1517.     if ((diff = tp1->t_time - tp2->t_time) > 0)
  1518.         return 1;
  1519.     else if (diff < 0)
  1520.         return -1;
  1521.     /*
  1522.     ** Oops!
  1523.     */
  1524.     if (tp1->t_rp->r_type == tp2->t_rp->r_type)
  1525.         cp = "duplicate rule?!";
  1526.     else    cp = "inconsistent rules?!";
  1527.     filename = tp1->t_rp->r_filename;
  1528.     linenum = tp1->t_rp->r_linenum;
  1529.     error(cp);
  1530.     filename = tp2->t_rp->r_filename;
  1531.     linenum = tp2->t_rp->r_linenum;
  1532.     error(cp);
  1533.     wildexit(cp);
  1534.     /*NOTREACHED*/
  1535. }
  1536.  
  1537. static
  1538. addrule(rp, y)
  1539. register struct rule *    rp;
  1540. long            y;
  1541. {
  1542.     if (ntemps >= TZ_MAX_TIMES) {
  1543.         error("too many transitions?!");
  1544.         wildexit("large number of transitions");
  1545.     }
  1546.     temps[ntemps].t_time = rpytime(rp, y);
  1547.     temps[ntemps].t_rp = rp;
  1548.     ++ntemps;
  1549. }
  1550.  
  1551. static
  1552. outzone(zp)
  1553. register struct zone *    zp;
  1554. {
  1555.     register struct rule *        rp;
  1556.     register int            i, j;
  1557.     register long            y;
  1558.     register long            gmtoff;
  1559.     char                buf[BUFSIZ];
  1560.  
  1561.     h.tzh_timecnt = 0;
  1562.     h.tzh_typecnt = 0;
  1563.     h.tzh_charcnt = 0;
  1564.     if (zp->z_nrules == 0) {    /* Piece of cake! */
  1565.         h.tzh_timecnt = 0;
  1566.         h.tzh_typecnt = 1;
  1567.         ttis[0].tt_gmtoff = zp->z_gmtoff;
  1568.         ttis[0].tt_isdst = 0;
  1569.         ttis[0].tt_abbrind = 0;
  1570.         newabbr(zp->z_format);
  1571.         writezone(zp->z_name);
  1572.         return;
  1573.     }
  1574.     /*
  1575.     ** See what the different local time types are.
  1576.     ** Plug the indices into the rules.
  1577.     */
  1578.     for (i = 0; i < zp->z_nrules; ++i) {
  1579.         rp = &zp->z_rules[i];
  1580.         (void) sprintf(buf, zp->z_format, rp->r_abbrvar);
  1581.         gmtoff = tadd(zp->z_gmtoff, rp->r_stdoff);
  1582.         for (j = 0; j < h.tzh_typecnt; ++j) {
  1583.             if (gmtoff == ttis[j].tt_gmtoff &&
  1584.                 strcmp(buf, &chars[ttis[j].tt_abbrind]) == 0)
  1585.                     break;
  1586.         }
  1587.         if (j >= h.tzh_typecnt) {
  1588.             if (h.tzh_typecnt >= TZ_MAX_TYPES) {
  1589.                 filename = zp->z_filename;
  1590.                 linenum = zp->z_linenum;
  1591.                 error("large number of local time types");
  1592.                 wildexit("input data");
  1593.             }
  1594.             ttis[j].tt_gmtoff = gmtoff;
  1595.             ttis[j].tt_isdst = rp->r_stdoff != 0;
  1596.             ttis[j].tt_abbrind = h.tzh_charcnt;
  1597.             newabbr(buf);
  1598.             ++h.tzh_typecnt;
  1599.         }
  1600.         rp->r_type = j;
  1601.     }
  1602.     /*
  1603.     ** Now. . .finally. . .generate some useable data!
  1604.     */
  1605.     ntemps = 0;
  1606.     for (i = 0; i < zp->z_nrules; ++i) {
  1607.         rp = &zp->z_rules[i];
  1608.         filename = rp->r_filename;
  1609.         linenum = rp->r_linenum;
  1610.         if (rp->r_yrtype != NULL && *rp->r_yrtype != '\0')
  1611.             hard(rp);
  1612.         else for (y = rp->r_loyear; y <= rp->r_hiyear; ++y)
  1613.             addrule(rp, y);
  1614.     }
  1615.     h.tzh_timecnt = ntemps;
  1616.     (void) qsort((char *) temps, ntemps, sizeof *temps, tcomp);
  1617.     for (i = 0; i < ntemps; ++i) {
  1618.         rp = temps[i].t_rp;
  1619.         filename = rp->r_filename;
  1620.         linenum = rp->r_linenum;
  1621.         types[i] = rp->r_type;
  1622.         ats[i] = tadd(temps[i].t_time, -zp->z_gmtoff);
  1623.         if (!rp->r_todisstd) {
  1624.             /*
  1625.             ** Credit to munnari!kre for pointing out the need for
  1626.             ** the following.  (This can still mess up on the
  1627.             ** earliest rule; who's got the solution?  It can also
  1628.             ** mess up if a time switch results in a day switch;
  1629.             ** this is left as an exercise for the reader.)
  1630.             */
  1631.             if (i == 0) {
  1632.                 /*
  1633.                 ** Kludge--not guaranteed to work.
  1634.                 */
  1635.                 if (ntemps > 1)
  1636.                     ats[0] = tadd(ats[0],
  1637.                         -temps[1].t_rp->r_stdoff);
  1638.             } else    ats[i] = tadd(ats[i],
  1639.                 -temps[i - 1].t_rp->r_stdoff);
  1640.         }
  1641.     }
  1642.     writezone(zp->z_name);
  1643.     return;
  1644. }
  1645.  
  1646. static
  1647. hard(rp)
  1648. register struct rule *    rp;
  1649. {
  1650.     register FILE *    fp;
  1651.     register int    n;
  1652.     long        y;
  1653.     char        buf[BUFSIZ];
  1654.     char        command[BUFSIZ];
  1655.  
  1656.     (void) sprintf(command, "years %ld %ld %s",
  1657.         rp->r_loyear, rp->r_hiyear, rp->r_yrtype);
  1658.     if ((fp = popen(command, "r")) == NULL)
  1659.         wild2exit("result opening pipe to", command);
  1660.     for (n = 0; fgets(buf, sizeof buf, fp) == buf; ++n) {
  1661.         if (strchr(buf, '\n') == 0)
  1662.             wildrexit(command);
  1663.         *strchr(buf, '\n') = '\0';
  1664.         if (sscanf(buf, scheck(buf, "%ld"), &y) != 1)
  1665.             wildrexit(command);
  1666.         if (y < rp->r_loyear || y > rp->r_hiyear)
  1667.             wildrexit(command);
  1668.         addrule(rp, y);
  1669.     }
  1670.     if (ferror(fp))
  1671.         wild2exit("result reading from", command);
  1672.     if (pclose(fp))
  1673.         wild2exit("result closing pipe to", command);
  1674.     if (n == 0) {
  1675.         error("no year in range matches type");
  1676.         wildexit("input data");
  1677.     }
  1678. }
  1679.  
  1680. static
  1681. lowerit(a)
  1682. {
  1683.     return (isascii(a) && isupper(a)) ? tolower(a) : a;
  1684. }
  1685.  
  1686. static
  1687. ciequal(ap, bp)        /* case-insensitive equality */
  1688. register char *    ap;
  1689. register char *    bp;
  1690. {
  1691.     while (lowerit(*ap) == lowerit(*bp++))
  1692.         if (*ap++ == '\0')
  1693.             return TRUE;
  1694.     return FALSE;
  1695. }
  1696.  
  1697. static
  1698. isabbr(abbr, word)
  1699. register char *        abbr;
  1700. register char *        word;
  1701. {
  1702.     if (lowerit(*abbr) != lowerit(*word))
  1703.         return FALSE;
  1704.     ++word;
  1705.     while (*++abbr != '\0')
  1706.         do if (*word == '\0')
  1707.             return FALSE;
  1708.                 while (lowerit(*word++) != lowerit(*abbr));
  1709.     return TRUE;
  1710. }
  1711.  
  1712. static struct lookup *
  1713. byword(word, table)
  1714. register char *            word;
  1715. register struct lookup *    table;
  1716. {
  1717.     register struct lookup *    foundlp;
  1718.     register struct lookup *    lp;
  1719.  
  1720.     if (word == NULL || table == NULL)
  1721.         return NULL;
  1722.     foundlp = NULL;
  1723.     for (lp = table; lp->l_word != NULL; ++lp)
  1724.         if (ciequal(word, lp->l_word))        /* "exact" match */
  1725.             return lp;
  1726.         else if (!isabbr(word, lp->l_word))
  1727.             continue;
  1728.         else if (foundlp == NULL)
  1729.             foundlp = lp;
  1730.         else    return NULL;        /* two inexact matches */
  1731.     return foundlp;
  1732. }
  1733.  
  1734. static char **
  1735. getfields(cp)
  1736. register char *    cp;
  1737. {
  1738.     register char *        dp;
  1739.     register char **    array;
  1740.     register int        nsubs;
  1741.  
  1742.     if (cp == NULL)
  1743.         return NULL;
  1744.     array = (char **) emalloc((strlen(cp) + 1) * sizeof *array);
  1745.     nsubs = 0;
  1746.     for ( ; ; ) {
  1747.         while (isascii(*cp) && isspace(*cp))
  1748.             ++cp;
  1749.         if (*cp == '\0' || *cp == '#')
  1750.             break;
  1751.         array[nsubs++] = dp = cp;
  1752.         do {
  1753.             if ((*dp = *cp++) != '"')
  1754.                 ++dp;
  1755.             else while ((*dp = *cp++) != '"')
  1756.                 if (*dp != '\0')
  1757.                     ++dp;
  1758.                 else    error("Odd number of quotation marks");
  1759.         } while (*cp != '\0' && *cp != '#' &&
  1760.             (!isascii(*cp) || !isspace(*cp)));
  1761.         if (isascii(*cp) && isspace(*cp))
  1762.             ++cp;
  1763.         *dp++ = '\0';
  1764.     }
  1765.     array[nsubs] = NULL;
  1766.     return array;
  1767. }
  1768.  
  1769. static long
  1770. tadd(t1, t2)
  1771. long    t1;
  1772. long    t2;
  1773. {
  1774.     register long    t;
  1775.  
  1776.     t = t1 + t2;
  1777.     if (t1 > 0 && t2 > 0 && t <= 0 || t1 < 0 && t2 < 0 && t >= 0) {
  1778.         error("time overflow");
  1779.         wildexit("time overflow");
  1780.     }
  1781.     return t;
  1782. }
  1783.  
  1784. static
  1785. isleap(y)
  1786. long    y;
  1787. {
  1788.     return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
  1789. }
  1790.  
  1791. static long
  1792. rpytime(rp, wantedy)
  1793. register struct rule *    rp;
  1794. register long        wantedy;
  1795. {
  1796.     register long    i, y, wday, t, m;
  1797.     register long    dayoff;            /* with a nod to Margaret O. */
  1798.  
  1799.     dayoff = 0;
  1800.     m = TM_JANUARY;
  1801.     y = EPOCH_YEAR;
  1802.     while (wantedy != y) {
  1803.         if (wantedy > y) {
  1804.             i = DAYS_PER_YEAR;
  1805.             if (isleap(y))
  1806.                 ++i;
  1807.             ++y;
  1808.         } else {
  1809.             --y;
  1810.             i = -DAYS_PER_YEAR;
  1811.             if (isleap(y))
  1812.                 --i;
  1813.         }
  1814.         dayoff = tadd(dayoff, i);
  1815.     }
  1816.     while (m != rp->r_month) {
  1817.         i = mon_lengths[m];
  1818.         if (m == TM_FEBRUARY && isleap(y))
  1819.             ++i;
  1820.         dayoff = tadd(dayoff, i);
  1821.         ++m;
  1822.     }
  1823.     i = rp->r_dayofmonth;
  1824.     if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
  1825.         if (rp->r_dycode == DC_DOWLEQ)
  1826.             --i;
  1827.         else {
  1828.             error("use of 2/29 in non leap-year");
  1829.             for ( ; ; )
  1830.                 wildexit("data");
  1831.         }
  1832.     }
  1833.     --i;
  1834.     dayoff = tadd(dayoff, i);
  1835.     if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
  1836.         wday = EPOCH_WDAY;
  1837.         /*
  1838.         ** Don't trust mod of negative numbers.
  1839.         */
  1840.         if (dayoff >= 0)
  1841.             wday = (wday + dayoff) % 7;
  1842.         else {
  1843.             wday -= ((-dayoff) % 7);
  1844.             if (wday < 0)
  1845.                 wday += 7;
  1846.         }
  1847.         while (wday != rp->r_wday) {
  1848.             if (rp->r_dycode == DC_DOWGEQ)
  1849.                 i = 1;
  1850.             else    i = -1;
  1851.             dayoff = tadd(dayoff, i);
  1852.             wday = (wday + i + 7) % 7;
  1853.         }
  1854.     }
  1855.     t = dayoff * SECS_PER_DAY;
  1856.     /*
  1857.     ** Cheap overflow check.
  1858.     */
  1859.     if (t / SECS_PER_DAY != dayoff)
  1860.         error("time overflow");
  1861.     return tadd(t, rp->r_tod);
  1862. }
  1863.  
  1864. static
  1865. newabbr(string)
  1866. char *    string;
  1867. {
  1868.     register int    i;
  1869.  
  1870.     i = strlen(string);
  1871.     if (h.tzh_charcnt + i >= TZ_MAX_CHARS)
  1872.         error("long time zone abbreviations");
  1873.     (void) strcpy(&chars[h.tzh_charcnt], string);
  1874.     h.tzh_charcnt += i + 1;
  1875. }
  1876.  
  1877. static
  1878. mkdirs(name)
  1879. char *    name;
  1880. {
  1881.     register char *    cp;
  1882.  
  1883.     if ((cp = name) == NULL || *cp == '\0')
  1884.         return;
  1885.     while ((cp = strchr(cp + 1, '/')) != 0) {
  1886.         *cp = '\0';
  1887.         (void) mkdir(name);
  1888.         *cp = '/';
  1889.     }
  1890. }
  1891. SHAR_EOF
  1892. if test 24558 -ne "`wc -c < 'tzcomp.c'`"
  1893. then
  1894.     echo shar: error transmitting "'tzcomp.c'" '(should have been 24558 characters)'
  1895. fi
  1896. fi
  1897. echo shar: extracting "'scheck.c'" '(1141 characters)'
  1898. if test -f 'scheck.c'
  1899. then
  1900.     echo shar: will not over-write existing file "'scheck.c'"
  1901. else
  1902. cat << \SHAR_EOF > 'scheck.c'
  1903. #
  1904.  
  1905. /*LINTLIBRARY*/
  1906.  
  1907. #include "stdio.h"
  1908.  
  1909. #ifdef OBJECTID
  1910. static char    sccsid[] = "@(#)scheck.c    7.9";
  1911. #endif
  1912.  
  1913. #include "ctype.h"
  1914.  
  1915. #ifndef alloc_t
  1916. #define alloc_t    unsigned
  1917. #endif
  1918.  
  1919. #ifndef MAL
  1920. #define MAL    NULL
  1921. #endif
  1922.  
  1923. extern char *    malloc();
  1924.  
  1925. char *
  1926. scheck(string, format)
  1927. char *    string;
  1928. char *    format;
  1929. {
  1930.     register char *    fbuf;
  1931.     register char *    fp;
  1932.     register char *    tp;
  1933.     register int    c;
  1934.     register char *    result;
  1935.     char        dummy;
  1936.  
  1937.     result = "";
  1938.     if (string == NULL || format == NULL)
  1939.         return result;
  1940.     fbuf = malloc((alloc_t) (2 * strlen(format) + 4));
  1941.     if (fbuf == MAL)
  1942.         return result;
  1943.     fp = format;
  1944.     tp = fbuf;
  1945.     while ((*tp++ = c = *fp++) != '\0') {
  1946.         if (c != '%')
  1947.             continue;
  1948.         if (*fp == '%') {
  1949.             *tp++ = *fp++;
  1950.             continue;
  1951.         }
  1952.         *tp++ = '*';
  1953.         if (*fp == '*')
  1954.             ++fp;
  1955.         while (isascii(*fp) && isdigit(*fp))
  1956.             *tp++ = *fp++;
  1957.         if (*fp == 'l' || *fp == 'h')
  1958.             *tp++ = *fp++;
  1959.         else if (*fp == '[')
  1960.             do *tp++ = *fp++;
  1961.                 while (*fp != '\0' && *fp != ']');
  1962.         if ((*tp++ = *fp++) == '\0')
  1963.             break;
  1964.     }
  1965.     *(tp - 1) = '%';
  1966.     *tp++ = 'c';
  1967.     *tp++ = '\0';
  1968.     if (sscanf(string, fbuf, &dummy) != 1)
  1969.         result = format;
  1970.     free(fbuf);
  1971.     return result;
  1972. }
  1973. SHAR_EOF
  1974. if test 1141 -ne "`wc -c < 'scheck.c'`"
  1975. then
  1976.     echo shar: error transmitting "'scheck.c'" '(should have been 1141 characters)'
  1977. fi
  1978. fi
  1979. echo shar: extracting "'strchr.c'" '(419 characters)'
  1980. if test -f 'strchr.c'
  1981. then
  1982.     echo shar: will not over-write existing file "'strchr.c'"
  1983. else
  1984. cat << \SHAR_EOF > 'strchr.c'
  1985. #
  1986.  
  1987. /*LINTLIBRARY*/
  1988.  
  1989. #include "stdio.h"
  1990.  
  1991. #ifdef OBJECTID
  1992. static char    sccsid[] = "@(#)strchr.c    7.3";
  1993. #endif
  1994.  
  1995. /*
  1996. ** For the benefit of BSD folks.
  1997. ** This is written from the manual description,
  1998. ** so there's no guarantee that it works the same as the "real thing."
  1999. */
  2000.  
  2001. char *    
  2002. strchr(string, c)
  2003. register char *    string;
  2004. register int    c;
  2005. {
  2006.     do if (*string == c)
  2007.         return string;
  2008.             while (*string++ != '\0');
  2009.     return NULL;
  2010. }
  2011. SHAR_EOF
  2012. if test 419 -ne "`wc -c < 'strchr.c'`"
  2013. then
  2014.     echo shar: error transmitting "'strchr.c'" '(should have been 419 characters)'
  2015. fi
  2016. fi
  2017. echo shar: extracting "'mkdir.c'" '(524 characters)'
  2018. if test -f 'mkdir.c'
  2019. then
  2020.     echo shar: will not over-write existing file "'mkdir.c'"
  2021. else
  2022. cat << \SHAR_EOF > 'mkdir.c'
  2023. #
  2024.  
  2025. /*LINTLIBRARY*/
  2026.  
  2027. #include "stdio.h"
  2028.  
  2029. #ifdef OJBECTID
  2030. static char    sccsid[] = "@(#)mkdir.c    7.2";
  2031. #endif
  2032.  
  2033. extern FILE *    popen();
  2034.  
  2035. mkdir(name)
  2036. char *    name;
  2037. {
  2038.     register FILE *    fp;
  2039.     register int    c;
  2040.     register int    oops;
  2041.  
  2042.     if ((fp = popen("sh", "w")) == NULL)
  2043.         return -1;
  2044.     (void) fputs("mkdir 2>&- '", fp);
  2045.     if (name != NULL)
  2046.         while ((c = *name++) != '\0')
  2047.             if (c == '\'')
  2048.                 (void) fputs("'\\''", fp);
  2049.             else    (void) fputc(c, fp);
  2050.     (void) fputs("'\n", fp);
  2051.     oops = ferror(fp);
  2052.     return (pclose(fp) == 0 && !oops) ? 0 : -1;
  2053. }
  2054. SHAR_EOF
  2055. if test 524 -ne "`wc -c < 'mkdir.c'`"
  2056. then
  2057.     echo shar: error transmitting "'mkdir.c'" '(should have been 524 characters)'
  2058. fi
  2059. fi
  2060. echo shar: extracting "'tzdump.c'" '(2783 characters)'
  2061. if test -f 'tzdump.c'
  2062. then
  2063.     echo shar: will not over-write existing file "'tzdump.c'"
  2064. else
  2065. cat << \SHAR_EOF > 'tzdump.c'
  2066. #
  2067.  
  2068. #include "stdio.h"
  2069.  
  2070. #ifdef OBJECTID
  2071. static char    sccsid[] = "@(#)tzdump.c    2.1";
  2072. #endif
  2073.  
  2074. #include "time.h"
  2075. #include "tzfile.h"
  2076.  
  2077. #ifndef alloc_t
  2078. #define alloc_t        unsigned
  2079. #endif
  2080.  
  2081. #ifndef TRUE
  2082. #define TRUE        1
  2083. #define FALSE        0
  2084. #endif
  2085.  
  2086. extern char *        asctime();
  2087. extern char *        calloc();
  2088. extern struct tm *    gmtime();
  2089. extern char *        newctime();
  2090. extern int        optind;
  2091. extern char *        sprintf();
  2092. extern long        time();
  2093. extern char *        tz_abbr;
  2094.  
  2095. static int        longest;
  2096.  
  2097. main(argc, argv)
  2098. int    argc;
  2099. char *    argv[];
  2100. {
  2101.     register FILE *    fp;
  2102.     register long *    tp;
  2103.     register int    i, j, c;
  2104.     register int    vflag;
  2105.     long        now;
  2106.     struct tzhead    h;
  2107.     char        buf[BUFSIZ];
  2108.  
  2109.     vflag = 0;
  2110.     while ((c = getopt(argc, argv, "v")) == 'v')
  2111.         vflag = 1;
  2112.     if (c != EOF || optind == argc - 1 && strcmp(argv[optind], "=") == 0) {
  2113.         (void) fprintf(stderr, "%s: usage is %s [ -v ] zonename ...\n",
  2114.             argv[0], argv[0]);
  2115.         exit(1);
  2116.     }
  2117.     (void) time(&now);
  2118.     longest = 0;
  2119.     for (i = optind; i < argc; ++i)
  2120.         if (strlen(argv[i]) > longest)
  2121.             longest = strlen(argv[i]);
  2122.     for (i = optind; i < argc; ++i) {
  2123.         if (settz(argv[i]) != 0) {
  2124.             (void) fprintf(stderr,
  2125.                 "%s: wild result from settz(\"%s\")\n",
  2126.                 argv[0], argv[i]);
  2127.             exit(1);
  2128.         }
  2129.         show(argv[i], now, FALSE);
  2130.         if (!vflag)
  2131.             continue;
  2132.         if (argv[i][0] == '/')
  2133.             fp = fopen(argv[i], "r");
  2134.         else {
  2135.             j = strlen(TZDIR) + 1 + strlen(argv[i]) + 1;
  2136.             if (j > sizeof buf) {
  2137.                 (void) fprintf(stderr,
  2138.                     "%s: wild long timezone name %s\n",
  2139.                     argv[0], argv[i]);
  2140.                 exit(1);
  2141.             }
  2142.             (void) sprintf(buf, "%s/%s", TZDIR, argv[i]);
  2143.             fp = fopen(buf, "r");
  2144.         }
  2145.         if (fp == NULL) {
  2146.             (void) fprintf(stderr,
  2147.                 "%s: wild result opening %s file\n",
  2148.                 argv[0], argv[i]);
  2149.             exit(1);
  2150.         }
  2151.         if (fread((char *) &h, sizeof h, 1, fp) != 1) {
  2152.             (void) fprintf(stderr,
  2153.                 "%s: wild result reading %s file\n",
  2154.                 argv[0], argv[i]);
  2155.             exit(1);
  2156.         }
  2157.         tp = (long *) calloc((alloc_t) h.tzh_timecnt, sizeof *tp);
  2158.         if (tp == NULL) {
  2159.             (void) fprintf(stderr,
  2160.                 "%s: wild result from calloc\n", argv[0]);
  2161.             exit(1);
  2162.         }
  2163.         if (h.tzh_timecnt != 0)
  2164.             if (fread((char *) tp, sizeof *tp, (int) h.tzh_timecnt,
  2165.                 fp) != h.tzh_timecnt) {
  2166.                 (void) fprintf(stderr,
  2167.                     "%s: wild result reading %s file\n",
  2168.                     argv[0], argv[i]);
  2169.                 exit(1);
  2170.             }
  2171.         if (fclose(fp)) {
  2172.             (void) fprintf(stderr,
  2173.                 "%s: wild result closing %s file\n",
  2174.                 argv[0], argv[i]);
  2175.             exit(1);
  2176.         }
  2177.         for (j = 0; j < h.tzh_timecnt; ++j) {
  2178.             show(argv[i], tp[j] - 1, TRUE);
  2179.             show(argv[i], tp[j], TRUE);
  2180.         }
  2181.         free((char *) tp);
  2182.     }
  2183.     return 0;
  2184. }
  2185.  
  2186. static
  2187. show(zone, t, v)
  2188. char *    zone;
  2189. long    t;
  2190. {
  2191.     (void) printf("%-*s  ", longest, zone);
  2192.     if (v)
  2193.         (void) printf("%.24s GMT = ", asctime(gmtime(&t)));
  2194.     (void) printf("%.24s", newctime(&t));
  2195.     if (*tz_abbr != '\0')
  2196.         (void) printf(" %s", tz_abbr);
  2197.     (void) printf("\n");
  2198. }
  2199. SHAR_EOF
  2200. if test 2783 -ne "`wc -c < 'tzdump.c'`"
  2201. then
  2202.     echo shar: error transmitting "'tzdump.c'" '(should have been 2783 characters)'
  2203. fi
  2204. fi
  2205. echo shar: extracting "'settz.c'" '(4052 characters)'
  2206. if test -f 'settz.c'
  2207. then
  2208.     echo shar: will not over-write existing file "'settz.c'"
  2209. else
  2210. cat << \SHAR_EOF > 'settz.c'
  2211. #
  2212.  
  2213. /*LINTLIBRARY*/
  2214.  
  2215. /*
  2216. ** Should there be any built-in rules other than GMT?
  2217. ** In particular, should zones such as "EST5" (abbreviation is always "EST",
  2218. ** GMT offset is always 5 hours) be built in?
  2219. */
  2220.  
  2221. #include "tzfile.h"
  2222. #include "time.h"
  2223.  
  2224. #ifdef OBJECTID
  2225. static char    sccsid[] = "@(#)settz.c    2.1";
  2226. #endif
  2227.  
  2228. #ifndef TRUE
  2229. #define TRUE        1
  2230. #define FALSE        0
  2231. #endif
  2232.  
  2233. #ifndef MAXPATHLEN
  2234. #define MAXPATHLEN    1024
  2235. #endif
  2236.  
  2237. extern char *        asctime();
  2238. extern struct tm *    gmtime();
  2239. extern char *        strcpy();
  2240. extern char *        strcat();
  2241. extern char *        getenv();
  2242.  
  2243. static struct tzhead    h;
  2244. static long        ats[TZ_MAX_TIMES];
  2245. static unsigned char    types[TZ_MAX_TIMES];
  2246. static struct ttinfo    ttis[TZ_MAX_TYPES];
  2247. static char        chars[TZ_MAX_CHARS + 1];
  2248.  
  2249. #define TZ_MAX_TOTAL    (sizeof h + sizeof ats + sizeof types + \
  2250.                 sizeof ttis + sizeof chars)
  2251.  
  2252. static char        isset;
  2253.  
  2254. char *            tz_abbr;    /* set by localtime; available to all */
  2255.  
  2256. /*
  2257. ** Not available west of the Rockies. . .
  2258. */
  2259.  
  2260. static char *
  2261. memcpy(to, from, n)
  2262. char *    to;
  2263. char *    from;
  2264. {
  2265.     register int    i;
  2266.  
  2267.     for (i = 0; i < n; ++i)
  2268.         to[i] = from[i];
  2269.     return to;
  2270. }
  2271.  
  2272. static
  2273. tzload(tzname)
  2274. register char *    tzname;
  2275. {
  2276.     register char *    p;
  2277.     register int    fid;
  2278.     register int    i;
  2279.     register int    doaccess;
  2280.     char        buf[(TZ_MAX_TOTAL>MAXPATHLEN)?TZ_MAX_TOTAL:MAXPATHLEN];
  2281.  
  2282.     if (tzname == 0 && (tzname = TZDEFAULT) == 0)
  2283.         return -1;
  2284.     doaccess = tzname[0] == '/';
  2285.     if (!doaccess) {
  2286.         if ((p = TZDIR) == 0)
  2287.             return -1;
  2288.         if ((strlen(p) + strlen(tzname) + 1) >= sizeof buf)
  2289.             return -1;
  2290.         (void) strcpy(buf, p);
  2291.         (void) strcat(buf, "/");
  2292.         (void) strcat(buf, tzname);
  2293.         /*
  2294.         ** Set doaccess if '.' (as in "../") shows up in name.
  2295.         */
  2296.         while (*tzname != '\0')
  2297.             if (*tzname++ == '.')
  2298.                 doaccess = TRUE;
  2299.         tzname = buf;
  2300.     }
  2301.     if (doaccess && access(tzname, 4) != 0)
  2302.         return -1;
  2303.     if ((fid = open(tzname, 0)) == -1)
  2304.         return -1;
  2305.     p = buf;
  2306.     i = read(fid, p, sizeof buf);
  2307.     if (close(fid) != 0 || i < sizeof h)
  2308.         return -1;
  2309.     (void) memcpy((char *) &h, p, sizeof h);
  2310.     if (h.tzh_timecnt > TZ_MAX_TIMES ||
  2311.         h.tzh_typecnt == 0 || h.tzh_typecnt > TZ_MAX_TYPES ||
  2312.         h.tzh_charcnt > TZ_MAX_CHARS)
  2313.             return -1;
  2314.     if (i < sizeof h +
  2315.         h.tzh_timecnt * (sizeof ats[0] + sizeof types[0]) +
  2316.         h.tzh_typecnt * sizeof ttis[0] +
  2317.         h.tzh_charcnt * sizeof chars[0])
  2318.             return -1;
  2319.     p += sizeof h;
  2320.     if ((i = h.tzh_timecnt) > 0) {
  2321.         (void) memcpy((char *) ats, p, i * sizeof ats[0]);
  2322.         p += i * sizeof ats[0];
  2323.         (void) memcpy((char *) types, p, i * sizeof types[0]);
  2324.         p += i * sizeof types[0];
  2325.     }
  2326.     if ((i = h.tzh_typecnt) > 0) {
  2327.         (void) memcpy((char *) ttis, p, i * sizeof ttis[0]);
  2328.         p += i * sizeof ttis[0];
  2329.     }
  2330.     if ((i = h.tzh_charcnt) > 0)
  2331.         (void) memcpy((char *) chars, p, i * sizeof chars[0]);
  2332.     chars[h.tzh_charcnt] = '\0';    /* ensure '\0'-termination */
  2333.     for (i = 0; i < h.tzh_timecnt; ++i)
  2334.         if (types[i] >= h.tzh_typecnt)
  2335.             return -1;
  2336.     for (i = 0; i < h.tzh_typecnt; ++i)
  2337.         if (ttis[i].tt_abbrind >= h.tzh_charcnt)
  2338.             return -1;
  2339.     return 0;
  2340. }
  2341.  
  2342. /*
  2343. ** settz("")        Use built-in GMT.
  2344. ** settz((char *) 0)    Use TZDEFAULT.
  2345. ** settz(otherwise)    Use otherwise.
  2346. */
  2347.  
  2348. settz(tzname)
  2349. char *    tzname;
  2350. {
  2351.     register int    answer;
  2352.  
  2353.     isset = TRUE;
  2354.     if (tzname != 0 && *tzname == '\0')
  2355.         answer = 0;            /* Use built-in GMT */
  2356.     else {
  2357.         if (tzload(tzname) == 0)
  2358.             return 0;
  2359.         /*
  2360.         ** If we want to try for local time on errors. . .
  2361.         if (tzload((char *) 0) == 0)
  2362.             return -1;
  2363.         */
  2364.         answer = -1;
  2365.     }
  2366.     h.tzh_timecnt = 0;
  2367.     ttis[0].tt_gmtoff = 0;
  2368.     ttis[0].tt_abbrind = 0;
  2369.     (void) strcpy(chars, "GMT");
  2370.     return answer;
  2371. }
  2372.  
  2373. struct tm *
  2374. newlocaltime(timep)
  2375. long *    timep;
  2376. {
  2377.     register struct ttinfo *    ttip;
  2378.     register struct tm *        tmp;
  2379.     register int            i;
  2380.     long                t;
  2381.  
  2382.     t = *timep;
  2383.     if (!isset)
  2384.         (void) settz(getenv("TZ"));
  2385.     if (h.tzh_timecnt == 0 || t < ats[0])
  2386.         i = 0;
  2387.     else {
  2388.         for (i = 1; i < h.tzh_timecnt; ++i)
  2389.             if (t < ats[i])
  2390.                 break;
  2391.         i = types[i - 1];
  2392.     }
  2393.     ttip = &ttis[i];
  2394.     t += ttip->tt_gmtoff;
  2395.     tmp = gmtime(&t);
  2396.     tmp->tm_isdst = ttip->tt_isdst;
  2397.     tz_abbr = &chars[ttip->tt_abbrind];
  2398.     return tmp;
  2399. }
  2400.  
  2401. char *
  2402. newctime(timep)
  2403. long *    timep;
  2404. {
  2405.     return asctime(newlocaltime(timep));
  2406. }
  2407. SHAR_EOF
  2408. if test 4052 -ne "`wc -c < 'settz.c'`"
  2409. then
  2410.     echo shar: error transmitting "'settz.c'" '(should have been 4052 characters)'
  2411. fi
  2412. fi
  2413. echo shar: extracting "'years.sh'" '(382 characters)'
  2414. if test -f 'years.sh'
  2415. then
  2416.     echo shar: will not over-write existing file "'years.sh'"
  2417. else
  2418. cat << \SHAR_EOF > 'years.sh'
  2419. : '@(#)years.sh    2.1'
  2420.  
  2421. : years lo hi type
  2422.  
  2423. case $# in
  2424.     3)        ;;
  2425.     *)        echo "$0: usage is $0 lo hi type" 1>&2
  2426.             exit 1 ;;
  2427. esac
  2428.  
  2429. lo="$1"
  2430. hi="$2"
  2431. type="$3"
  2432.  
  2433. case $type in
  2434.     uspres)        check='(y % 4) == 0' ;;
  2435.     nonpres)    check='(y % 4) != 0' ;;    
  2436.     *)        echo "$0: wild year type ($type)" 1>&2
  2437.             exit 1 ;;
  2438. esac
  2439.  
  2440. exec awk "
  2441. BEGIN {
  2442.     for (y = $lo; y <= $hi; ++y)
  2443.         if ($check)
  2444.             print y;
  2445.     exit
  2446. }
  2447. "
  2448. SHAR_EOF
  2449. if test 382 -ne "`wc -c < 'years.sh'`"
  2450. then
  2451.     echo shar: error transmitting "'years.sh'" '(should have been 382 characters)'
  2452. fi
  2453. fi
  2454. echo shar: extracting "'asia'" '(71 characters)'
  2455. if test -f 'asia'
  2456. then
  2457.     echo shar: will not over-write existing file "'asia'"
  2458. else
  2459. cat << \SHAR_EOF > 'asia'
  2460. # @(#)asia    2.1
  2461. # Zone    NAME        GMTOFF    RULES    FORMAT
  2462. Zone    Japan        9:00    -    JST
  2463. SHAR_EOF
  2464. if test 71 -ne "`wc -c < 'asia'`"
  2465. then
  2466.     echo shar: error transmitting "'asia'" '(should have been 71 characters)'
  2467. fi
  2468. fi
  2469. echo shar: extracting "'australasia'" '(942 characters)'
  2470. if test -f 'australasia'
  2471. then
  2472.     echo shar: will not over-write existing file "'australasia'"
  2473. else
  2474. cat << \SHAR_EOF > 'australasia'
  2475. # @(#)australasia    2.1
  2476.  
  2477. # Australian Data (for states with DST), standard rules
  2478.  
  2479. # Rule    NAME    FROM    TO    TYPE    IN    ON    AT    SAVE    LETTER/S
  2480. Rule    Aus    1971    2037    -    Oct    lastSun    2:00    1:00    -
  2481. Rule    Aus    1972    only    -    Feb    27    3:00    0    -
  2482. Rule    Aus    1973    2037    -    Mar    Sun>=1    3:00    0    -
  2483.  
  2484. #Australian Data, Vic (and NSW except for a variation in 83? that I[kre] forget)
  2485.  
  2486. Rule    Aus-Vic    1971    2037    -    Oct    lastSun    2:00    1:00    -
  2487. Rule    Aus-Vic    1972    only    -    Feb    27    3:00    0    -
  2488. Rule    Aus-Vic    1973    1985    -    Mar    Sun>=1    3:00    0    -
  2489. # is this really forever, or just 86??
  2490. Rule    Aus-Vic    1986    2037    -    Mar    Sun<=21    3:00    0    -
  2491.  
  2492. # Australia - something of a turmoil here
  2493. # Zone    NAME        GMTOFF    RULES    FORMAT
  2494. Zone    EST        10:00    Aus-Vic    EST    # rule change, 1986
  2495. Zone    Tasmania    10:00    Aus    EST    # still the standard rules?
  2496. Zone    Queensland    10:00    -    EST    # Queensland - no DST
  2497. Zone    CST        9:30    Aus    CST    # still the standard rules?
  2498. Zone    North        9:30    -    CST    # Northern Territory - no DST
  2499. Zone    WST        8:00    -    WST    # No DST ever, this is simple...
  2500. SHAR_EOF
  2501. if test 942 -ne "`wc -c < 'australasia'`"
  2502. then
  2503.     echo shar: error transmitting "'australasia'" '(should have been 942 characters)'
  2504. fi
  2505. fi
  2506. echo shar: extracting "'europe'" '(930 characters)'
  2507. if test -f 'europe'
  2508. then
  2509.     echo shar: will not over-write existing file "'europe'"
  2510. else
  2511. cat << \SHAR_EOF > 'europe'
  2512. # @(#)europe    2.1
  2513.  
  2514. # European data is hearsay...
  2515.  
  2516. # Rule    NAME    FROM    TO    TYPE    IN    ON    AT    SAVE    LETTER/S
  2517. Rule    W-Eur    1969    2037    -    Mar    lastSun    2:00    1:00    " DST"
  2518. Rule    W-Eur    1969    1982    -    Oct    lastSun    2:00    0    -
  2519. Rule    W-Eur    1983    only    -    Oct    23    2:00    0    -
  2520. Rule    W-Eur    1984    2037    -    Oct    lastSun    2:00    0    -
  2521.  
  2522. Rule    M-Eur    1969    2037    -    Mar    lastSun    2:00    1:00    " DST"
  2523. Rule    M-Eur    1969    1982    -    Sep    lastSun    2:00    0    -
  2524. Rule    M-Eur    1983    only    -    Oct    23    2:00    0    -
  2525. Rule    M-Eur    1984    2037    -    Sep    lastSun    2:00    0    -
  2526.  
  2527. # Zone    NAME        GMTOFF    RULES    FORMAT
  2528. Zone    WET        0    W-Eur    WET%s
  2529. Zone    MET        1     M-Eur    MET%s
  2530.  
  2531. # One source shows that Bulgaria, Cyprus, Finland, and Greece observe DST from
  2532. # the last Sunday in March to the last Sunday in September in 1986.
  2533. # Did any/all of them have Middle Europe's 1983 wobble?
  2534. #
  2535. # The source shows Romania changing a day later than everybody else;
  2536. # since I don't think they're allowed to have UNIX(tm) systems, we'll skip
  2537. # them for now.
  2538.  
  2539. Zone    EET        2    M-Eur    EET%s
  2540. SHAR_EOF
  2541. if test 930 -ne "`wc -c < 'europe'`"
  2542. then
  2543.     echo shar: error transmitting "'europe'" '(should have been 930 characters)'
  2544. fi
  2545. fi
  2546. echo shar: extracting "'etcetera'" '(1208 characters)'
  2547. if test -f 'etcetera'
  2548. then
  2549.     echo shar: will not over-write existing file "'etcetera'"
  2550. else
  2551. cat << \SHAR_EOF > 'etcetera'
  2552. # @(#)etcetera    2.1
  2553.  
  2554. #
  2555. # A settz("") uses the code's built-in GMT without going to disk to get
  2556. # the information.  Still, we want things to work if somebody does a
  2557. # settz("GMT"), so. . .
  2558. #
  2559.  
  2560. Zone    GMT        0    -    GMT
  2561.  
  2562. #
  2563. # Names for zones that might exist, just so people can set a timezone
  2564. # that's right for their area, even if it doesn't have a name or dst rules
  2565. # (half hour zones are too much to bother with -- when someone asks!)
  2566. #
  2567.  
  2568. Zone    GMT-12        -12    -    GMT-1200
  2569. Zone    GMT-11        -11    -    GMT-1100
  2570. Zone    GMT-10        -10    -    GMT-1000
  2571. Zone    GMT-9        -9    -    GMT-0900
  2572. Zone    GMT-8        -8    -    GMT-0800
  2573. Zone    GMT-7        -7    -    GMT-0700
  2574. Zone    GMT-6        -6    -    GMT-0600
  2575. Zone    GMT-5        -5    -    GMT-0500
  2576. Zone    GMT-4        -4    -    GMT-0400
  2577. Zone    GMT-3        -3    -    GMT-0300
  2578. Zone    GMT-2        -2    -    GMT-0200
  2579. Zone    GMT-1        -1    -    GMT-0100
  2580. Zone    GMT+1        1    -    GMT+0100
  2581. Zone    GMT+2        2    -    GMT+0200
  2582. Zone    GMT+3        3    -    GMT+0300
  2583. Zone    GMT+4        4    -    GMT+0400
  2584. Zone    GMT+5        5    -    GMT+0500
  2585. Zone    GMT+6        6    -    GMT+0600
  2586. Zone    GMT+7        7    -    GMT+0700
  2587. Zone    GMT+8        8    -    GMT+0800
  2588. Zone    GMT+9        9    -    GMT+0900
  2589. Zone    GMT+10        10    -    GMT+1000
  2590. Zone    GMT+11        11    -    GMT+1100
  2591. Zone    GMT+12        12    -    GMT+1200
  2592. Zone    GMT+13        13    -    GMT+1300    # GMT+12 with DST
  2593.  
  2594. Link    GMT        UTC        # one of these two is right, but which?
  2595. Link    GMT        UCT
  2596. Link    GMT        Universal
  2597. Link    GMT        Greenwich
  2598. SHAR_EOF
  2599. if test 1208 -ne "`wc -c < 'etcetera'`"
  2600. then
  2601.     echo shar: error transmitting "'etcetera'" '(should have been 1208 characters)'
  2602. fi
  2603. fi
  2604. echo shar: extracting "'northamerica'" '(3139 characters)'
  2605. if test -f 'northamerica'
  2606. then
  2607.     echo shar: will not over-write existing file "'northamerica'"
  2608. else
  2609. cat << \SHAR_EOF > 'northamerica'
  2610. # @(#)northamerica    2.1
  2611.  
  2612. # Bob Devine has written that ". . .your table is wrong for MostNA in 1974.
  2613. # The correct ending date is 10/27 not 11/24."  Yet on a 4.1bsd VAX/11-750
  2614. # system, compiling and executing the program
  2615. #
  2616. #    #include "time.h"
  2617. #
  2618. #    long l = 152592000;
  2619. #
  2620. #    main() {
  2621. #        struct tm *    tmp;
  2622. #
  2623. #        tmp = localtime(&l);
  2624. #        printf("%s", asctime(tmp));
  2625. #        printf("isdst: %d\n", tmp->tm_isdst);
  2626. #    }
  2627. #
  2628. # results in the output
  2629. #
  2630. #    Fri Nov  1 22:40:00 1974
  2631. #    isdst: 1
  2632. #
  2633. # For now we'll stay with 4.1bsd's version.
  2634. #
  2635. # Note also this from munnari!kre:
  2636. # "I recall also being told by someone once that Canada didn't have
  2637. # the DST variations in 74/75 that the US did, but I am not nearly
  2638. # sure enough of this to add anything."
  2639.  
  2640. # Before the Uniform Time Act of 1966 took effect in 1967, observance of
  2641. # Daylight Saving Time in the US was by local option, except during wartime.
  2642.  
  2643. # Rule    NAME    FROM    TO    TYPE    IN    ON    AT    SAVE    LETTER/S
  2644. Rule    MostNA    1918    1919    -    Mar    lastSun    2:00    1:00    D
  2645. Rule    MostNA    1918    1919    -    Oct    lastSun    2:00    0    S
  2646. Rule    MostNA    1942    only    -    Feb    9    2:00    1:00    W # War
  2647. Rule    MostNA    1945    only    -    Sep    30    2:00    0    S
  2648. Rule    MostNA    1967    1973    -    Apr    lastSun    2:00    1:00    D
  2649. Rule    MostNA    1967    1973    -    Oct    lastSun    2:00    0    S
  2650. Rule    MostNA    1974    only    -    Jan    6    2:00    1:00    D
  2651. Rule    MostNA    1974    only    -    Nov    24    2:00    0    S
  2652. Rule    MostNA    1975    only    -    Feb    23    2:00    1:00    D
  2653. Rule    MostNA    1975    only    -    Oct    26    2:00    0    S
  2654. Rule    MostNA    1976    2037    -    Apr    lastSun    2:00    1:00    D
  2655. Rule    MostNA    1976    2037    -    Oct    lastSun    2:00    0    S
  2656.  
  2657. ###############################################################################
  2658.  
  2659. # New names
  2660.  
  2661. # Zone    NAME        GMTOFF    RULES    FORMAT
  2662. Zone    Atlantic    -4:00    MostNA    A%sT
  2663. Zone    Eastern        -5:00    MostNA    E%sT
  2664. Zone    Central        -6:00    MostNA    C%sT
  2665. Zone    Mountain    -7:00    MostNA    M%sT
  2666. Zone    Pacific        -8:00    MostNA    P%sT
  2667. Zone    Yukon        -9:00    MostNA    Y%sT
  2668. Zone    Aleutian    -10:00    MostNA    A%sT
  2669. Zone    Newfoundland    -3:30    -    NST    # Is DST now observed here?
  2670.                         # If so, when did it start?
  2671.  
  2672. # Old names
  2673.  
  2674. # Link    LINK-FROM    LINK-TO
  2675. Link    Eastern        EST5EDT
  2676. Link    Central        CST6CDT
  2677. Link    Mountain    MST7MDT
  2678. Link    Pacific        PST8PDT
  2679.  
  2680. # Nonstandard mainland areas:
  2681.  
  2682. Rule    SomeUS    1918    1919    -    Mar    lastSun    2:00    1:00    D
  2683. Rule    SomeUS    1918    1919    -    Oct    lastSun    2:00    0    S
  2684. Rule    SomeUS    1942    only    -    Feb    9    2:00    1:00    W # War
  2685. Rule    SomeUS    1945    only    -    Sep    30    2:00    0    S
  2686.  
  2687. Zone    East-Indiana    -5:00    SomeUS    E%sT # Usually standard near South Bend
  2688. Zone    Arizona        -7:00    SomeUS    M%sT # Usually standard in Arizona
  2689.  
  2690. # And then there's Hawaii.
  2691. # DST was observed for one day in 1933.
  2692. # Standard time was change by half an hour in 1947; this accounts for
  2693. # the half-hour offsets before then, and the peculiar first rule.
  2694. # (An alternative is to have "Zone Hawaiian -10:30..." with a
  2695. # current standard offset of 0:30; this seems a bit more obscure.)
  2696. #
  2697. # Things have been calm since 1947.
  2698.  
  2699. Rule    Hawaii    1901    only    -    Dec    14    0:00    -0:30    S
  2700. Rule    Hawaii    1918    1919    -    Mar    lastSun    2:00    0:30    D
  2701. Rule    Hawaii    1918    1919    -    Oct    lastSun    2:00    -0:30    S
  2702. Rule    Hawaii    1933    only    -    Apr    30    2:00    0:30    D
  2703. Rule    Hawaii    1933    only    -    May    1    2:00    -0:30    S
  2704. Rule    Hawaii    1942    only    -    Feb    9    2:00    0:30    W # War
  2705. Rule    Hawaii    1945    only    -    Sep    30    2:00    -0:30    S
  2706. Rule    Hawaii    1947    only    -    Jun    8    2:00    0    S
  2707.  
  2708. Zone    Hawaiian    -10:00    Hawaii    H%sT
  2709. SHAR_EOF
  2710. if test 3139 -ne "`wc -c < 'northamerica'`"
  2711. then
  2712.     echo shar: error transmitting "'northamerica'" '(should have been 3139 characters)'
  2713. fi
  2714. fi
  2715. echo shar: extracting "'pacificnew'" '(922 characters)'
  2716. if test -f 'pacificnew'
  2717. then
  2718.     echo shar: will not over-write existing file "'pacificnew'"
  2719. else
  2720. cat << \SHAR_EOF > 'pacificnew'
  2721. # @(#)pacificnew    2.1
  2722.  
  2723. # "Pacific Presidential Election Time" is being contemplated by the US Congress
  2724.  
  2725. # Rule    NAME    FROM    TO    TYPE    IN    ON    AT    SAVE    LETTER/S
  2726. Rule    Twilite    1918    1919    -    Mar    lastSun    2:00    1:00    D
  2727. Rule    Twilite    1918    1919    -    Oct    lastSun    2:00    0    S
  2728. Rule    Twilite    1942    only    -    Feb    9    2:00    1:00    W # War
  2729. Rule    Twilite    1945    only    -    Sep    30    2:00    0    S
  2730. Rule    Twilite    1967    1973    -    Apr    lastSun    2:00    1:00    D
  2731. Rule    Twilite    1967    1973    -    Oct    lastSun    2:00    0    S
  2732. Rule    Twilite    1974    only    -    Jan    6    2:00    1:00    D
  2733. Rule    Twilite    1974    only    -    Nov    24    2:00    0    S
  2734. Rule    Twilite    1975    only    -    Feb    23    2:00    1:00    D
  2735. Rule    Twilite    1975    only    -    Oct    26    2:00    0    S
  2736. Rule    Twilite    1976    2037    -    Apr    lastSun    2:00    1:00    D
  2737. Rule    Twilite    1976    1987    -    Oct    lastSun    2:00    0    S
  2738. Rule    Twilite    1988    2037    uspres    Oct    lastSun    2:00    1:00    PE
  2739. Rule    Twilite    1988    2037    uspres    Nov    Sun>=7    2:00    0    S
  2740. Rule    Twilite    1988    2037    nonpres    Oct    lastSun    2:00    0    S
  2741.  
  2742. # Zone    NAME        GMTOFF    RULES    FORMAT
  2743. Zone    Pacific-New    -8:00    Twilite    P%sT
  2744. SHAR_EOF
  2745. if test 922 -ne "`wc -c < 'pacificnew'`"
  2746. then
  2747.     echo shar: error transmitting "'pacificnew'" '(should have been 922 characters)'
  2748. fi
  2749. fi
  2750. exit 0
  2751. #    End of shell archive
  2752.